convert iso time strings to valid momentjs format and compare them - javascript

I want to compare some times with momentjs. These times come from time pickers and use the ISO 8601 format, 24hr hh:mm (more info here).
I want to compare the examples "01:45" and "13:36". Using the function isSameOrBefore should return me true. Unfortunately
const valid = moment("01:45").isSameOrBefore("13:36")
does not work, because the iso strings use a wrong format. I get the warning
Deprecation warning: value provided is not in a recognized RFC2822 or
ISO format. moment construction falls back to js Date()
I tried to go for this
const isoFormat = 'hh:mm'
const first = "01:45"
const second = "13:36"
const firstBeforeSecond = moment(first, isoFormat).isBefore(second, isoFormat)
console.log(firstBeforeSecond)
<script src="https://cdn.jsdelivr.net/npm/moment#2.24.0/moment.min.js"></script>
but this still fails. The value I get returned is false and this is not correct. What is the correct way to compare these time strings?

Using moment for this is huge overkill
Just compare strings
"01:45" < "13:36"
is true
"13:36" === "13:36"
is also true
the reason is that in ISO 8601 the strings have the same length and hence will
"00:00" always be the lowest value and "23:59" the highest.
This is safe because they stay string and have ":" in them, so will not be cast to number or lose the leading 0s or such

The correct syntax is:
moment(first, isoFormat).isBefore(moment(second, isoFormat))

try this
var first = moment('01:45', 'hh:mm');
var second = moment('13:36', 'hh:mm');
console.log(first. isSameOrBefore(second));
specifying format will not give any warnings :)

Related

Using Angular DateTime pipe programmatically for hh:mm:ss formats

I'm trying use DatePipe for HH:MM:SS (or any other documented formats) just as I've used DecimalPipe for monetary values.
However, passing my logic a format such as hh:mm:ss my values immediately turn to 07:00:00.
time = 'hh:mm:ss';
val = '1:02'; // user entered value
invalids = new RegExp('[^0-9:]{0,6}', 'g'); // time chars only
replaced = String(val).replace(invalids, ''); // remove non-hhmmss characters
let value = this.datePipe.transform(replaced, time); // format the value
console.log(value); // '07:00:00' why!?
Here is the repro in StackBlitz:67
How can I get the component to accept those predefined formats to force the input value?
Angular DatePipe's input is typed as any, but actually requires a Date, or miliseconds, or ISO formatted string which you are not giving it.
https://angular.io/api/common/DatePipe#input-value
value any The date expression: a Date object, a number (milliseconds
since UTC epoch), or an ISO string
(https://www.w3.org/TR/NOTE-datetime).
The data you are passing in does not meet that criteria so it's probably not going to work for you use case unless you can modify it before sending to datePipe.

Why new Date doesn't work in Firefox browser

I want to check difference between given date and now. I want to use exactly the code below and it works fine in chrome. but the console log says something else in Firefox.
Why? and how to fix this?
// input your custom Date below
const date = new Date('2020-6-23 14:22:00 GMT+0430'); // Set End Time Here!
const dif = (date.getTime() / 1000) - ((new Date().getTime())/1000);
const end = Math.max(0, dif);
console.log(date, dif, end);
"GMT" does not belong in that string. The string should be ISO 8601 compliant, if you want to be sure that it gets parsed correctly.
To align it with the ISO standard:
remove "GMT" and the space before it,
separate the time part from the date part with a "T",
write the month with double digits.
Either use punctuation (hyphen, colon) in the date, time and timezone, or don't use any at all. This condition is not really clear in the ISO 8601 specs I have access to, but apparently there is a move towards a more strict definition which excludes using punctuation only in a part of the string. In short, you are sure to align when you add also a colon in +04:30.
const date = new Date('2020-06-23T14:22:00+04:30');
// Now also output it in the Iranian timezone:
console.log(date.toLocaleString("en", { timeZone: "Iran" } ));
BTW: GMT is an ambiguous term anyway. UTC is a more exact defined term.

Why moment(date).isValid() returns wrong result

when I check the following date it returns true result, Why?
const value = "3";
if (moment(new Date(value), "DD-MM-YYYY HH:mm", true).isValid()) // true
{ }
or
const value = "3";
if (moment(new Date(value)).isValid()) // true
{ }
That is because new Date("3") is valid date and
console.log(new Date("3"))
This is one of those cases that shows you need to sanitize your date strings and should not depend on the native parser, unless you are sure your strings have already been validated and are conformant.
ECMA-262 Date(value) constructor specs
Date.parse
If the String does not conform to that format the function may fall back to any implementation-specific heuristics or implementation-specific date formats.
So it's not conformant to "Date Time String Format", which requires the string to start with "YYYY", so it goes to an implementation specific parsing that is similar to the rules for above, but using the form: "MM-DD-YYYY".
The purpose of using strict mode (setting third argument of moment() to true) is to let moment do the string parsing and determine if it fits the formats that you provide (to for example avoid unexpected parsing behavior like this). If you use Date() to parse, you are no longer using moment's strict mode to validate the string fits your required format.
let value = "3";
function checkDate(value){
console.log(value,
moment(value, "DD-MM-YYYY HH:mm", true).isValid() ? 'valid' : 'invalid')
}
value = "01-01-2011 11:22"
checkDate(value)
value = "01-01-2011 11:22Z"
checkDate(value)
value = "3"
checkDate(value)
value = new Date("3").toString()
checkDate(value)
value = new Date('INVALID DATE')
checkDate(value)
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.25.3/moment-with-locales.min.js" integrity="sha256-8d6kI5cQEwofkZmaPTRbKgyD70GN5mDpTYNP9YWhTlI=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.28/moment-timezone-with-data.js" integrity="sha256-O1PdKrSbpAYWSBteb7yX/CMmHhu3US31mtCbsryGwaY=" crossorigin="anonymous"></script>
If you don't need to validate the date string (for example to prevent unexpected parsing behavior), don't need to worry about non-modern browsers, and really just need to parse conforming Date strings and format to basic string formats, you could just use native Date() with Intl.DateTimeFormat or Date.prototype.toLocaleString.
TL;DR the way you are using it right now implies that you don't actually need moment
Because 3 is a valid Date, the Date also supports only the year or only month format.
If you try new Date("YYYY") --> It's a valid date
If you try new Date("MM") --> It's a valid format
So, for new Date("{1 to 12}") It will accept
For new Date("{13 to 31}") It's invalid
Also, from new Date("{32 to 49}") It considers as year, for two digits it will add the current century that is (2000 + number you specified), for e.g.
new Date("32") is the year 2032 and for new Date("{50 to 99}") it adds in the previous century i.e. (1900 + number you specified), for e.g. new Date("99") is the year "1999"
For three-digit, till "100000" on-wards it's pretty straightforward what input it is will be a year, for e.g. new Date("100") is year 100 and new Date("100000") is the year 100000. The rest are invalid.
The above is valid as of today, instead of taking care of the above information it's always advisable to use Null, NaN, and Undefined values where the date field is not present

Parse JSON DateTime object to local time in JQuery by ignoring timezone

I am facing an issue while parsing JSON Date Time object using moment(of course I tried many approaches suggested in Stackoverflow but nothing worked in my case).
In my application, I'm storing a DateTime value as UTC DateTime. Now when I'm displaying I need to display it according to the browser timezone. After going through many StackOverflow questions, I used "moment.js" as below
//From server, the Date object looks like /Date(1506510057813)/
//The equivalent DateTime value stored in Database is 2017-09-27 13:00:57.813
fuction DateTimeFormatter(value)
{
if (value != undefined) {
var newValue = new Date(moment.utc(value));
//But at this line, even with just moment(value) all I am getting is DateTime which is not same as UTC time.
//I don't want any time zone to get appended all I want is just 13:00:57
var newHours = newValue.getHours() - newValue.getTimezoneOffset() / 60;
var newMinutes = (newHours + '.0').split('.')[1] * 6;
newValue.setHours(newHours);
newValue.setMinutes(newMinutes);
return moment(newValue).format(applicationTableDateFormat);
}
else
return "";
}
Please let me know what I am doing wrong or is there any other way I can display time as per browser time zone.
Once you have a UTC moment, you can convert it to local.
moment.utc(value).local().format(...)
https://momentjs.com/docs/#/manipulating/local/
But it sounds like maybe your real problem is when you store the date. If you're storing it as UTC, make sure you actually convert the local value to UTC before you store it. That way when you read it, you get a predictable value that you can safely convert to any locale.
Angularjs has its own mechanism to display formatted dates on views you just needs an absolute representation of a date and it takes care of the rest. And by absolute, I mean, a Date which is settled in a timezone whether it's utc or not, you need to know what timezone you are talking about.
The date filter
It's a filter from the core module of angularjs and it accepts:
"... either as Date object, milliseconds (string or number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.sssZ and its shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ). If no timezone is specified in the string input, the time is considered to be in the local timezone." (Angularjs date filter)
The problem
Angularjs need a proper date input in order to display it correctly, in your case you seem to have the milliseconds format (sort of, /Date(1506510057813)/), you could use that and extract the numeric part and input that on the pipe, or you can change the server to send the ISO 8601 date (a.k.a., yyyy-MM-ddTHH:mm:ss.sssZ).
For example:
let rawDate = '/Date(1506510057813)/';
let re = /\/Date\((\d+)\)\//g; // regex to extract number from the string date
let myDate = new Date(Number(re.exec()[1])) // extract the milliseconds
Or
let rawDate = '2017-09-27T11:00:57.813Z';
let myDate = new Date(rawDate)// and you don't need to do anything else
Either way you'd end up with something like this:
<span> {{ myDate | date }}</span>

Reading UTC time strings

Hi I'm trying to read some UTC data strings using moments.js.
e.g.
date1 = moment.utc("160114224512Z").format('YYYY-MM-DD HH:mm:ss');
console.log(date1)
However, this always throws an invalid date error
Moment will accept unix timestamps in both seconds and milliseconds as strings, if you specify the x or X token. You actually don't even need to strip the Z - the regular expression related to the x and X tokens is looking for a number, so it will ignore the Z by default.
I think you have milliseconds there, so you would use the small x token, as follows:
moment.utc("160114224512Z", 'x').format('YYYY-MM-DD HH:mm:ss');
"1975-01-28 04:10:24"
That look right?
As an additional note, it might be good to strip the Z for purposes of clarity, even if you don't have to.
I'm going to assume you have quotes you haven't shown, e.g.:
date1 = moment.utc("160114224512Z").format('YYYY-MM-DD HH:mm:ss');
// Note -----------^-------------^
console.log(date1)
The problem is simple: That isn't a valid date/time string, in any format I've ever seen. It's certainly not ISO-8601, for instance.
It looks like a seconds-since-the-Epoch value for Jan 28th, 1975, since it's just a number and it's too big to be milliseconds-since-the-Epoch (unless you really have a date in the year 7043).
If it's seconds-since-the-epoch, ditch the Z and use it as a number:
date1 = moment.utc(160114224512).format('YYYY-MM-DD HH:mm:ss');
The string 160114224512Z is not a valid UTC moment format, nor a valid moment format.
I would advise you to specify your input format, I'd do:
moment.utc(160114224512, 'x').format('YYYY-MM-DD HH:mm:ss')

Categories