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.
Related
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 :)
I have a datetime from Apple's receipt validation server. I need to compare it to today's date. I'm trying to use moment.js but I am fine with native Date as well.
The date is formatted like this, in what Apple's docs claim, incorrectly, is RFC 3339 format:
2017-11-28 23:37:52 Etc/GMT
Since this isn't a valid RFC 3339 or ISO 8601 datetime, it is failing to parse using moment.js or Date.parse(). How can I parse it?
Note that I don't want to simply strip the Etc/ out because its important for determining the correct timezone according to https://opensource.apple.com/source/system_cmds/system_cmds-230/zic.tproj/datfiles/etcetera:
We use POSIX-style signs in the Zone names and the output abbreviations, even though this is the opposite of what many people expect. POSIX has positive signs west of Greenwich, but many people expect positive signs east of Greenwich. For example, TZ='Etc/GMT+4' uses the abbreviation "GMT+4" and corresponds to 4 hours behind UTC (i.e. west of Greenwich) even though many people would expect it to mean 4 hours ahead of UTC (i.e. east of Greenwich).
You can adopt one of two strategies:
Manually parse the string and use the parts for the Date constructor, then adjust for the timezone.
Transform the timestamp into a string that should be supported by most browsers in use (i.e. ISO 8601 extended format per ECMA-262).
The first way is more robust.
The reference doesn't say how timezones like +0530 are represented in the Etc/ format, so the following doesn't deal with them:
'Etc/GMT' becomes '+00:00'
'Etc/GMT+4' becomes '-04:00'
'Etc/GMT-10' becomes '+10:00'
Also, the following functions don't validate the format, they assume the supplied string is suitable.
// Parse strings in format 2017-11-28 23:37:52 Etc/GMT
function parsePOZIX(s) {
var b = s.split(' ');
// These are the date and time parts
var c = b[0].split(/\D/).concat(b[1].split(/\D/));
// Create a new Date using UTC
var d = new Date(Date.UTC(c[0],c[1]-1,c[2],c[3],c[4],c[5]));
// Now adjust for the timezone
var tz = b[2].split('/')[1];
var sign = /^\+/.test(tz) ? 1 : -1;
var hr = tz.replace(/\D/g, '') || '0';
d.setUTCHours(d.getUTCHours() + sign*hr);
return d;
}
['2017-11-28 23:37:52 Etc/GMT',
'2017-11-28 23:37:52 Etc/+8',
'2017-11-28 23:37:52 Etc/-10'].forEach(function(s){
console.log(s + '\n' + parsePOZIX(s).toISOString());
});
And the second (less reliable way) which parses and reformats the string, then uses the built-in parser:
// Reformat strings like 2017-11-28 23:37:52 Etc/GMT
// to ISO 8601 compliance, then use built-in parser
function parsePOSIX2(s) {
var b = s.split(' ');
var tz = b[2].split('/')[1];
var sign = /^\+/.test(tz)? '-' : '+';
var hr = tz.replace(/\D/g,'') || '0';
hr = ('0' + hr).slice(-2) + ':00'; // Must include colon for Safari
return new Date(b[0] + 'T' + b[1] + sign + hr);
}
['2017-11-28 23:37:52 Etc/GMT',
'2017-11-28 23:37:52 Etc/-4'].forEach(function(s) {
console.log(s + '\n' + parsePOSIX2(s).toISOString());
});
Note that Safari will not parse a timezone like "+0000" (resulting in an invalid date), it must include a colon: "+00:00".
The easiest way to parse an an arbitrary format is to use some regex to split it to pieces, then arrange it in a format you can use.
const date = '2017-11-28 23:37:52 Etc/GMT';
const [,year,month,day,hour,minute,second,timezone] = date.match(/(\d{4})-(\d{2})-(\d{2})\s(\d{2}):(\d{2}):(\d{2})\sEtc\/([A-Z]{3})/);
console.log(year, month, day, hour, minute, second, timezone);
const parsedDate = new Date(`${year}-${month}-${day} ${hour}:${minute}:${second} ${timezone}`);
console.log(parsedDate);
The nice thing about this approach is it works for any random format you may come across (you just need a different regex). With ES6 destructing, it can be quite compact.
Note: I'm not sure if that Etc bit is constant or has special meaning, so you should check out the spec and make sure you don't need to do anything with it.
The format Apple is returning consists of an ISO 8601 datetime followed by an IANA timezone. That's an eccentric format I've never seen elsewhere, and it seems to be a mistake on Apple's part given that their docs claim it's meant to be an RFC 3339 datetime string.
JavaScript has no built-in support for working with IANA timezones. For that matter, nor does the core Moment.js library. However, Moment Timezone does. If you include both the moment and moment-timezone libraries, then you can parse your date like this:
/**
* Parse a datetime string returned from the Apple Receipt Validation Server, in
* a format like:
* 2017-11-28 23:37:52 Etc/GMT
* and return its value as a Moment datetime object.
*/
function parseAppleDatetime(appleDatetimeStr) {
const [dateStr, timeStr, timezoneStr] = appleDatetimeStr.split(' '),
datetimeStr = dateStr + ' ' + timeStr;
return moment.tz(datetimeStr, timezoneStr);
}
Now if you do, for instance:
parseAppleDatetime('2017-11-28 23:37:52 Etc/GMT').format()
... you'll get:
"2017-11-28T23:37:52Z"
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')
DOM:
<input id="myTextbox" type="datetime-local" />
Javascript (jQuery):
$('#myTextbox').val(new Date().toISOString());
Doesn't work. The format of input[type=datetime-local] is supposed to be ISO 8601, which is what javascript's Date.toISOString() returns.
Unfortunately, the previous answers did not work properly for me, because they suggest considering UTC time as my local time (which is, generally saying, incorrect).
For example, if my local time is 2021-03-10T01:50:55+0200, then date.toISOString() returns 2021-03-09T23:50:55Z, so I cannot just cut Z at the end, because for datetime-local I need local datetime 2021-03-10T01:50:55, NOT 2021-03-09T23:50:55.
So, the fixed code would be the following:
const d = new Date();
const dateTimeLocalValue = (new Date(d.getTime() - d.getTimezoneOffset() * 60000).toISOString()).slice(0, -1);
$('#myTextbox').val(dateTimeLocalValue);
That's why it works: we still use the trick of removing trailing "Z" from UTC's time format, but before doing it, we shift the time by our time zone offset (returning by date.getTimezoneOffset() in minutes) in the backward direction. After that, the shifted time, converted to UTC, provides the same date & time that our local. Of course, actually, the shifted time is a different moment, but we don't care as soon as its date & time in UTC matches our date & time in the local timezone.
With the example above, it works the following way:
shift local time by timezone offset in opposite direction (e.g. if it was UTC+2, then we make even further from UTC): 2021-03-10T01:50:55+0200 -> 2021-03-10T03:50:55+0200 (by - date.getTimezoneOffset() * 60000, because 1 minute is 60000 milliseconds)
return date&time values back by converting to UTC: 2021-03-10T03:50:55+0200 -> 2021-03-10T01:50:55Z (by .toISOString())
remove trailing Z to get real local time with the suited format for <input type="datetime-local"> (by .slice(0, -1))
If someone needs back transformation, from input value to js Date, then we just need to do the same steps in the reverse order:
const dateTimeLocalValue = $('#myTextbox').val();
const fakeUtcTime = new Date(`${dateTimeLocalValue}Z`);
const d = new Date(fakeUtcTime.getTime() + fakeUtcTime.getTimezoneOffset() * 60000);
console.log(d);
Any questions are welcome)
Update: this answer may set the date incorrectly (off by one day) based on your local time zone and time of day. See Maxim's answer for an explanation and a correct solution.
--
http://www.w3schools.com/jsref/jsref_toisostring.asp:
The toISOString() method converts a Date object into a string, using
the ISO standard.
The standard is called ISO-8601 and the format is:
YYYY-MM-DDTHH:mm:ss.sssZ
While ISO 8601 has some flexibility, the format of javascript's Date's toISOString() is exactly as shown above.
The 'Z' at the end means this is a UTC date. So, this representation includes timezone information. (Javascript dates are naturally in UTC time since they are internally represented as milliseconds since epoch.)
The format of HTML5 input with type=datetime-local must be ...
The following parts, in exactly the following order:
A date.
The literal string "T".
A time.
Example:
1985-04-12T23:20:50.52
1996-12-19T16:39:57
http://www.w3.org/TR/html-markup/input.datetime-local.html
This is still ISO 8601, but stricter, and it does not allow a timezone to be specified.
Luckily, removing the timezone is as easy as removing the trailing 'Z'.
var isoStr = new Date().toISOString();
$('#myTextbox').val(isoStr.substring(0,isoStr.length-1));
Date.toLocaleString can do the trick for you:
$('#myTextbox').val(new Date().toLocaleString("sv-SE", {
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit"
}).replace(" ", "T"));
This will work even in browsers that don't support datatime-local like Firefox-desktop and Safari-desktop.
For more information on date-related-inputs to js-date conversions check this article that I wrote on the topic.
Use $('#myTextbox')[0].valueAsNumber = new Date().getTime().
HTMLInputElement interface also has valueAsDate property, but type=datetime-local doesn't support it unfortunately.
https://html.spec.whatwg.org/C/#input-type-attr-summary
For me, I do like this:
const d = new Date()
element.value = `${d.toLocaleDateString().split("/").reverse().join("-")} ${d.toLocaleTimeString()}`
if dd = "2012-08-20 01:16:00";
converting this date to time-stamp (as in the following code)
var t = new Date(dd).getTime();
http://jsfiddle.net/userdude/DHxwR/
the result t = NaN why ?
According to ECMA-262 (§15.9.1.15, Date Time String Format, page 169), the only date string format required to be accepted is:
[+YY]YYYY[-MM[-DD]][THH:mm[:ss[.sss]]]Z
where Z is either Z (for UTC) or an offset consisting of either a + or a - followed by HH:mm. Any other formats that happen to be supported by a particular browser should not be relied upon, as continued support is not guaranteed.
Therefore, replace the space with a T and append either a Z, or a fixed time zone offset before passing it to the Date constructor. For example, if the date and time are in the UTC+8 zone:
var dd = "2012-08-20 01:16:00";
var t = new Date(dd.replace(' ', 'T') + '+08:00').getTime();
This will return the number of milliseconds from January 1, 1970, midnight UTC, to the date you have specified, treated as either universal time (if you appended Z) or a time local to the fixed time zone offset that you specify.
Please note that this will act differently in that the date is not simply treated as time local to the user's system time zone as your question's example does. However, I can't think of a situation where doing that would be useful, because you'd get different results depending on the user's configuration — but in reality, the time difference between two dates is always the same no matter where you are.
Try to use a space or comma between the year, month, and day values.
It's simple:
+(new Date("2012-08-20 01:16:00"));