Convert DateTime string to timestap in javascript - javascript

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"));

Related

Initializing time with its own timezone

I'm quite new (and confused) with time in JavaScript..
I currently have time data to work with, and they are in the format of DD-MMM-YYYY, meaning it would be 23-Feb-2021. This time is already in its own timezone, GMT-10. I'm trying to initialize it as GMT-10 so that I could get its appropriate epoch time.
I've done this:
date = new Date("23-Feb-2021") // This results in 2021-02-23T00:00:00.000Z
But what I'm trying to achieve is to get the time to be 2021-02-23T10:00:00.000Z, which I could then do a getTime() to get its epoch in ms. I understand I could probably hard code to +10 to the time I have, but the data I work with might vary so I'd like to figure a way to initialize the date with a specific timezone.
EDIT:
Here's an example of an outcome I'd want:
date = ("23-Feb-2021")
date = moment(date).format(); // 2021-02-23T00:00:00+00:00
date = date.replace("+00","+10");
date = new Date(msg.date); // 2021-02-22T14:00:00.000Z
date = date.getTime(); // 1614002400000 (2021-02-22T14:00:00.000Z)
In the end, 2021-02-22T14:00:00.000Z is what I'm trying to get, without having to iterate it a bunch of times like above and adding +10
You can add the timezone offset to your input string, and use an explicit string format to parse it:
let date = "23-Feb-2021"
date = moment(date + "-10:00", "D-MMM-YYYYZ")
console.log(date.format()) // 2021-02-23T11:00:00+01:00 (if local is GMT+1)
console.log(date.utc().format()) // 2021-02-23T10:00:00+00:00
It seems you're already using moment.js, so add moment–timezone so you can parse timestamps in whatever IANA timezone you want. You can either choose a location with the offset rules you want (e.g. Pacific/Honolulu or Pacific/Tahiti for -10) or just a fixed offset like etc/GMT+10.
You can then format the value in any timezone, as UTC, or as a time value, e.g.
// Timestamp
let d = "23-Feb-2021";
// Parse in specific IANA timezone
let m = moment.tz(d, 'D-MMM-YYYY', 'Pacific/Honolulu');
// Trigger UTC mode
m.utc()
// Show result
console.log(m.format())
// Get time value (ms since epoch)
console.log(m.valueOf());
// Parse using generic timezone/fixed offset
let g = moment.tz(d, 'D-MMM-YYYY', 'etc/GMT+10');
console.log(g.utc().format());
// Display timestamp for another timezone
console.log(moment.tz(g, 'Asia/Riyadh').format());
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.34/moment-timezone-with-data-10-year-range.js"></script>
Note that for fixed offset timezones like etc/GMT+10, the sign is the opposite of the common offset (e.g. etc/GMT+10 is UTC-10) to be consistent with POSIX notation. However, moment.tz only has limited POSIX support in that it only recognises one hour offsets, not the full POSIX timezone notation, so you can't do say "etc/GMT-530" instead of Asia/Kolkata.

Working with different timezones in Javascript

I am working on a cloud based application which deals extensively with date and time values, for users across the world.
Consider a scenario, in JavaScript, where my machine is in India (GMT+05:30), and I have to display a clock running in California's timezone (GMT-08:00).
In this case I have to get a new date object,
let india_date = new Date()
add it's time zone offset value,
let uts_ms = india_date.getTime() + india_date.getTimezoneOffset()
add california's timezone offset value,
let california_ms = utc_ms + getCaliforniaTimezoneOffsetMS()
and finally the date object.
let california_date: Date = new Date(california_ms)
Is there any way to directly deal with these kinds of time zones without having to convert the values again and again?
First, let's talk about the code in your question.
let india_date = new Date()
You have named this variable india_date, but the Date object will only reflect India if the code is run on a computer set to India's time zone. If it is run on a computer with a different time zone, it will reflect that time zone instead. Keep in mind that internally, the Date object only tracks a UTC based timestamp. The local time zone is applied when functions and properties that need local time are called - not when the Date object is created.
add it's timezone offset value
let uts_ms = india_date.getTime() + india_date.getTimezoneOffset()
This approach is incorrect. getTime() already returns a UTC based timestamp. You don't need to add your local offset. (also, the abbreviation is UTC, not UTS.)
Now add california's timezone offset value
let california_ms = utc_ms + getCaliforniaTimezoneOffsetMS()
Again, adding an offset is incorrect. Also, unlike India, California observes daylight saving time, so part of the year the offset will be 480 (UTC-8), and part of the year the offset will be 420 (UTC-7). Any function such as your getCaliforniatimezoneOffsetMS would need to have the timestamp passed in as a parameter to be effective.
and finally the date object
let california_date: Date = new Date(california_ms)
When the Date constructor is passed a numeric timestamp, it must be in terms of UTC. Passing it this california_ms timestamp is actually just picking a different point in time. You can't change the Date object's behavior to get it to use a different time zone just by adding or subtracting an offset. It will still use the local time zone of where it runs, for any function that requires a local time, such as .toString() and others.
There is only one scenario where this sort of adjustment makes sense, which is a technique known as "epoch shifting". The timestamp is adjusted to shift the base epoch away from the normal 1970-01-01T00:00:00Z, thus allowing one to take advantage of the Date object's UTC functions (such as getUTCHours and others). The catch is: once shifted, you can't ever use any of the local time functions on that Date object, or pass it to anything else that expects the Date object to be a normal one. Epoch shifting done right is what powers libraries like Moment.js. Here is another example of epoch shifting done correctly.
But in your example, you are shifting (twice in error) and then using the Date object as if it were normal and not shifted. This can only lead to errors, evident by the time zone shown in toString output, and will arise mathematically near any DST transitions of the local time zone and the intended target time zone. In general, you don't want to take this approach.
Instead, read my answer on How to initialize a JavaScript Date to a particular time zone. Your options are listed there. Thanks.
JavaScript Date objects store date and time in UTC but the toString() method is automatically called when the date is represented as a text value which displays the date and time in the browser's local time zone. So, when you want to convert a datetime to a time zone other than your local time, you are really converting from UTC to that time zone (not from your local time zone to another time zone).
If your use case is limited to specific browsers and you are flexible on formatting (since browsers may differ in how they display date string formats), then you may be able to use toLocaleString(), but browsers like Edge, Android webview, etc do not fully support the locales and options parameters.
Following example sets both the locale and timezone to output the date in a local format that may vary from browser to browser.
const dt = new Date();
const kolkata = dt.toLocaleString('en-IN', { timeZone: 'Asia/Kolkata' });
const la = dt.toLocaleString('en-US', { timeZone: 'America/Los_Angeles' });
console.log('Kolkata:', kolkata);
// example output: Kolkata: 19/3/2019, 7:36:26 pm
console.log('Los Angeles:', la);
// example output: Los Angeles: 3/19/2019, 7:06:26 AM
You could also use Moment.js and Moment Timezone to convert date and time to a time zone other than your local time zone. For example:
const dt = moment();
const kolkata = dt.tz('Asia/Kolkata').format();
const la = dt.tz('America/Los_Angeles').format();
console.log(kolkata);
// example output: 2019-03-19T19:37:11+05:30
console.log(la);
// example output: 2019-03-19T07:07:11-07:00
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.23/moment-timezone-with-data.min.js"></script>
Well, you really do kind of have to convert anytime you want to change the display, but it's not as bad as you think.
First, store all time as UTC. Probably using the milliseconds format, e.g. Date.UTC().
Second, do all manipulation / comparison using that stored info.
Third, if your cloud-based application has an API that API should only talk in terms of UTC as well, though you could provide the ISO string if you prefer that to the MS, or if you expect clients to handle that better.
Fourth and finally, only in the UI should you do the final conversion to the local date/time string, either with the method you're describing or using a library such as momentjs
new Date creates a Date object with a time value that is UTC. If you can guarantee support for the timeZone option of toLocaleString (e.g. corporate environment with a controlled SOE), you can use it to construct a timestamp in any time zone and any format, but it can be a bit tedious. Support on the general web may be lacking. A library would be preferred in that case if you need it to work reliably.
E.g. to get values for California, you can use toLocaleString and "America/Los_Angeles" for the timeZone option:
var d = new Date();
// Use the default implementation format
console.log(d.toLocaleString(undefined, {timeZone:'America/Los_Angeles'}));
// Customised format
var weekday = d.toLocaleString(undefined, {weekday:'long', timeZone:'America/Los_Angeles'});
var day = d.toLocaleString(undefined, {day:'numeric', timeZone:'America/Los_Angeles'});
var month = d.toLocaleString(undefined, {month:'long', timeZone:'America/Los_Angeles'});
var year = d.toLocaleString(undefined, {year:'numeric', timeZone:'America/Los_Angeles'});
var hour = d.toLocaleString(undefined, {hour:'numeric',hour12: false, timeZone:'America/Los_Angeles'});
var minute = d.toLocaleString(undefined, {minute:'2-digit', timeZone:'America/Los_Angeles'});
var ap = hour > 11? 'pm' : 'am';
hour = ('0' + (hour % 12 || 12)).slice(-2);
console.log(`The time in Los Angeles is ${hour}:${minute} ${ap} on ${weekday}, ${day} ${month}, ${year}`);
Getting the timezone name is a little more difficult, it's difficult to get it without other information.

Converting date from string with offset to different timezone

I'm wondering on the correct way to convert a string date in a non-ISO format to a different offset/timezone.
I am currently given 3 values:
the date in format MM/DD/YYYY (23/11/2016)
the time in 24h format (23:13)
timezone offset (-07:00)
I would like to convert said date to the user's timezone.
I am trying to convert the format to the format accepted by moment timezone's moment.tz() function ('2016-11-23T23:13-07:00') but I am not sure how to do that without splitting the date array and converting it to said date.
Moment's timezone has the tools I need to convert the date afterwards to the local timezone. For example:
moment.tz('2016-11-23T23:13-07:00', moment.tz.guess());
Any thoughts on how to convert 23/11/2016 23:13 with offset -07:00 to the local date preferably using momentJS?
Why not just format as an ISO 8601 string with offset and give that to moment.js?
function customToISOString(date, time, offset){
return date.split(/\D/).reverse().join('-') + 'T' + time + offset;
}
document.write(customToISOString('23/11/2016','23:13','-07:00')); // 2016-11-23T23:13-07:00
Most modern browsers will also parse that, but don't do it as there are still plenty of older browsers around where it will fail.
I like Rob's answer, but I'll also give you it in moment.js.
First, you don't need moment-timezone, and you definitely don't need to guess the time zone id just to convert to that zone. In ISO format, it would just be like this:
var m = moment('2016-11-23T23:13-07:00');
This will read in the offset during parsing, apply it, then convert to the local time zone, returning a moment object in "local mode". This is the default mode, so it just works.
With the requirements you described it would be like this:
// your inputs
var d = "23/11/2016";
var t = "23:13";
var o = "-07:00";
var m = moment(d + ' ' + t + o, 'MM/DD/YYYY HH:mmZ');
Note that I add the space between the date and time just for safety, so there's no risk of mixing the year and the hour components.
Again it will automatically apply the offset and convert to the local time zone, since that's the default behavior. If you want some other behavior, there are ways to do that as well.

Using momentjs to convert date to epoch then back to date

I'm trying to convert a date string to epoch, then epoch back to the date string to verify that I'm providing the correct date string.
var epoch = moment("10/15/2014 9:00").unix(); // do I need to do .local()?
var momentDate = moment(epoch); // I've also tried moment.utc(epoch)
var momentDateStr = momentDate.calendar();
alert("Values are: epoch = " + epoch + ", momentDateStr = " + momentDateStr);
Renders
Values are: epoch = 1413378000, momentDateStr = 01/17/1970
Note: I'm using the following version of the moment js script, //cdnjs.cloudflare.com/ajax/libs/moment.js/2.8.3/moment-with-locales.js
There are a few things wrong here:
First, terminology. "Epoch" refers to the starting point of something. The "Unix Epoch" is Midnight, January 1st 1970 UTC. You can't convert an arbitrary "date string to epoch". You probably meant "Unix Time", which is often erroneously called "Epoch Time".
.unix() returns Unix Time in whole seconds, but the default moment constructor accepts a timestamp in milliseconds. You should instead use .valueOf() to return milliseconds. Note that calling .unix()*1000 would also work, but it would result in a loss of precision.
You're parsing a string without providing a format specifier. That isn't a good idea, as values like 1/2/2014 could be interpreted as either February 1st or as January 2nd, depending on the locale of where the code is running. (This is also why you get the deprecation warning in the console.) Instead, provide a format string that matches the expected input, such as:
moment("10/15/2014 9:00", "M/D/YYYY H:mm")
.calendar() has a very specific use. If you are near to the date, it will return a value like "Today 9:00 AM". If that's not what you expected, you should use the .format() function instead. Again, you may want to pass a format specifier.
To answer your questions in comments, No - you don't need to call .local() or .utc().
Putting it all together:
var ts = moment("10/15/2014 9:00", "M/D/YYYY H:mm").valueOf();
var m = moment(ts);
var s = m.format("M/D/YYYY H:mm");
alert("Values are: ts = " + ts + ", s = " + s);
On my machine, in the US Pacific time zone, it results in:
Values are: ts = 1413388800000, s = 10/15/2014 9:00
Since the input value is interpreted in terms of local time, you will get a different value for ts if you are in a different time zone.
Also note that if you really do want to work with whole seconds (possibly losing precision), moment has methods for that as well. You would use .unix() to return the timestamp in whole seconds, and moment.unix(ts) to parse it back to a moment.
var ts = moment("10/15/2014 9:00", "M/D/YYYY H:mm").unix();
var m = moment.unix(ts);
http://momentjs.com/docs/#/displaying/unix-timestamp/
You get the number of unix seconds, not milliseconds!
You you need to multiply it with 1000 or using valueOf() and don't forget to use a formatter, since you are using a non ISO 8601 format. And if you forget to pass the formatter, the date will be parsed in the UTC timezone or as an invalid date.
moment("10/15/2014 9:00", "MM/DD/YYYY HH:mm").valueOf()

Get local time representation of Date in arbitrary timezone in arbitrary day - considering Daylight Savings Time

For sure, there is a lot of questions about Date objects and timezones but many of them are about converting the current time to another timezone, and others are not very clear about what they want to do.
I want to display the day, hour, minute etc. in an arbitrary timezone, in an arbitrary day. For example, I would like a function f(t, s) that:
given the timestamp 1357041600 (which is 2013/1/1 12:00:00 UTC) and the string "America/Los Angeles", would satisfy the comparison below:
f(1357041600, "America/Los Angeles") == "2013/01/01 04:00:00"
given the timestamp 1372680000 (2013/07/01 12:00:00 UTC), would satisfy the comparison below:
f(1357041600, "America/Los Angeles") == "2013/07/01 05:00:00"
will always behave this way even if the timezone in the browser is, let us say "Europe/London" or "America/São Paulo".
will always behave this way even if the time in the browser is, let us say 2014/02/05 19:32, or 2002/08/04 07:12; and
as a final restriction, will not request anything from the server side (because I'm almost doing it myself :) )
Is it even possible?
given the timestamp 1357041600 (which is 2013/1/1 12:00:00 UTC)
That appears to be seconds since the UNIX epoch (1970-01-01T00:00:00Z). Javascript uses the same epoch, but in milliseconds so to create a suitable date object:
var d = new Date(timestamp * 1000);
That will create a Date object with a suitable time value. You then need to determine the time zone offset using something like the IANA time zone database. That can be applied to the Date object using UTC methods. E.g. resolve the offset to minutes, then use:
d.setUTCMinutes(d.getUTCMinutes() + offset)
UTC methods can then be used to get the adjusted date and time values to create a string in whatever format you require:
var dateString = d.getUTCFullYear() + '/' + pad(d.getUTCMonth() + 1) + '/' ...
where pad is a function to add a leading zero to single digit values. Using UTC methods avoids any impact of local time zone offsets and daylight saving variances.
There are also libraries like timezone.js that can be used to determine the offset, however I have not used them so no endorsement is implied.
For JavaScript runtime environments that support the ECMAScript Internationalization API, and adhere to its recommendation of supporting the IANA time zone database, you can simply do this:
new Date(1357041600000).toLocaleString("en-US", {timeZone: "America/Los_Angeles"})
For other environments, a library is required. There are several listed here.

Categories