Trying to convert Unix Epoch time into UTC localized date/time string - javascript

My goal is to convert an integer expressing the Unix Epoch time (or the number of milliseconds since midnight of January 1, 1970) into a localized time for the UTC (or GMT) time-zone.
So I have this method:
function formatDateTimeFromTicks(nTicks)
{
//'nTicks' = number of milliseconds since midnight of January 1, 1970
//RETURN:
// = Formatted date/time
return new Date(nTicks).toLocaleString();
}
As an example I'm using the value of 1442004135000, which should give me ‎9‎/‎11‎/‎2015‎ 8‎:‎42‎:‎15‎ ‎PM for my locale (here's where you can check), but my method:
alert(formatDateTimeFromTicks(1442004135000));
gives me ‎‎9‎/‎11‎/‎2015‎ ‎1‎:‎42‎:‎15‎ ‎PM.
Any idea why and how to fix it?

The native Date object won't be enough, as even in the best case it doesn't give you a UTC and locale string. I strongly suggest you use the excellent moment library to have reliable behavior across all platforms.
To display nice localized UTC in French:
moment(1442004135000).utc().locale('fr').format('LLLL')
=> "vendredi 11 septembre 2015 20:42"

Related

Wrong unix time from parsed DateTime

Here is code
const dateStr = '1989-11-11T03:34';
let date = new Date(dateStr);
console.log(date.toUTCString());
console.log(+date);
And output:
Fri, 10 Nov 1989 22:34:00 GMT
626740440000 <--- far future
Why unix time is in far future?
Here is Playcode link
It's not wrong.
You seem to have two issues with what you're getting:
The time isn't the same in your toISOString output.
The number you're getting from +date isn't what you expect.
But both are correct:
The string has no timezone indicator on it, so since it's a date+time string, it's parsed as local time. This is covered by the Date Time String Format section of the specification. But your output is showing GMT (because toISOString uses GMT).
626740440000 is the number of milliseconds since The Epoch, not seconds as it was in the original Unix epoch scheme. This is covered by the Time Values and Time Range section of the specification.
If you want to parse your string as UTC (loosely, GMT), add a Z to the end of it indicating that't is in GMT.
If you want the number of seconds since The Epoch, divide +date by 1000 (perhaps rounding or flooring the result).

Alternative to casting UTC Date in Javascript?

I wish to create a new Date in JS, but have it be cast as UTC time. For example, suppose castAsUTC() produces the following desired effect:
var x = new Date('2019-01-01T00:00:00') // In local time (PST)
castAsUTC(x).toISOString(); // => '2019-01-01T00:00:00Z'
// x.toISOString() gives us '2019-01-01T08:00:00Z', which is undesired
Currently, my function looks like this:
function castAsUTC(date) {
return new Date(x.toLocaleString() + '+00:00');
}
Is there a cleaner/nicer way of producing the same effect? Thanks in advance!
EDIT: To be more specific, I'm interested in transforming the date's timezone, without changing its actual value with as little arithmetic as possible. So calling .toISOString() will produce the same date as it is in local time.
I am currently using the moment-timezone library, but I can't seem to get the desired effect using that, either. I would definitely accept an answer that uses Moment.js
You can switch a Moment instance to UTC using the utc function. Then just use format to get whatever the specific output you want from it.
If indeed the string you have is like the one shown, then the easiest thing to do would be to append a Z to indicate UTC.
var input = '2019-01-01T00:00:00';
var date = new Date(input + 'Z');
var output = date.toISOString();
Or, if you would like to use Moment.js, then do this:
var input = '2019-01-01T00:00:00';
var m = moment.utc(input);
var output = m.format();
You do not need moment-timezone for this.
tl;dr;
You formatted the date wrong. Add the letter "Z" to the end of your date string and it will be treated as UTC.
var x = new Date('2019-01-01T00:00:00Z') // Jan 1, 2019 12 AM UTC
These formatting issues are easier to manage with a library like momentjs (utc and format functions) as described in other answers. If you want to use vanilla javascript, you'll need to subtract out the timezone offset before calling toISOString (see warnings in the longer answer below).
Details
Date in javascript deals with timezones in a somewhat counter intuitive way. Internally, the date is stored as the number of milliseconds since the Unix epoch (Jan 1, 1970). That's the number you get when you call getTime() and it's the number that's used for math and comparisons.
However - when you use the standard string formatting functions (toString, toTimeString, toDateString, etc) javascript automatically applies the timezone offset for the local computers timezone before formatting. In a browser, that means it will apply the offset for the end users computer, not the server. The toISOString and toUTCString functions will not apply the offset - they print the actual UTC value stored in the Date. This will probably still look "wrong" to you because it won't match the value you see in the console or when calling toString.
Here's where things really get interesting. You can create Date's in javascript by specifying the number of milliseconds since the Unix epoch using new Date(milliseconds) or by using a parser with either new Date(dateString). With the milliseconds method, there's no timezone to worry about - it's defined as UTC. The question is, with the parse method, how does javascript determine which timezone you intended? Before ES5 (released 2009) the answer was different depending on the browser! Post ES5, the answer depends on how you format the string! If you use a simplified version of ISO 8601 (with only the date, no time), javascript considers the date to be UTC. Otherwise, if you specify the time in ISO 8601 format, or you use a "human readable" format, it considers the date to be local timezone. Check out MDN for more.
Some examples. I've indicated for each if javascript treats it as a UTC or a local date. In UTC, the value would be Jan 1, 1970 at midnight. In local it depends on the timezone. For OP in pacfic time (UTC-8), the UTC value would be Jan 1, 1970 at 8 AM.
new Date(0) // UTC (milliseconds is always UTC)
new Date("1/1/1970"); // Local - (human readable string)
new Date("1970-1-1"); // Local (invalid ISO 8601 - missing leading zeros on the month and day)
new Date("1970-01-01"); // UTC (valid simplified ISO 8601)
new Date("1970-01-01T00:00"); // Local (valid ISO 8601 with time and no timezone)
new Date("1970-01-01T00:00Z"); // UTC (valid ISO 8601 with UTC specified)
You cannot change this behavior - but you can be pedantic about the formats you use to parse dates. In your case, the problem was you provided an ISO-8601 string with the time component but no timezone. Adding the letter "Z" to the end of your string, or removing the time would both work for you.
Or, always use a library like momentjs to avoid these complexities.
Vanilla JS Workaround
As discussed, the real issue here is knowing whether a date will be treated as local or UTC. You can't "cast" from local to UTC because all Date's are UTC already - it's just formatting. However, if you're sure a date was parsed as local and it should really be UTC, you can work around it by manually adjusting the timezone offset. This is referred to as "epoch shifting" (thanks #MattJohnson for the term!) and it's dangerous. You actually create a brand new Date that refers to a different point in time! If you use it in other parts of your code, you can end up with incorrect values!
Here's a sample epoch shift method (renamed from castAsUtc for clarity). First get the timezone offset from the object, then subtract it and create a new date with the new value. If you combine this with toISOString you'll get a date formatted as you wanted.
function epochShiftToUtc(date) {
var timezoneOffsetMinutes = date.getTimezoneOffset();
var timezoneOffsetMill = timezoneOffsetMinutes * 1000 * 60;
var buffer = new Date(date.getTime() - timezoneOffsetMill);
return buffer;
}
epochShiftToUtc(date).toUTCString();

Send JavaScript date with milliseconds and timezone to Java webservice

I need to send my current date on UI as http request header to Java based webservice but facing issue as the javascript new Date method hides the millisecond data from date and forwards it to web service.
console.log(new Date())
LOGS - Thu Sep 07 2017 14:47:37 GMT+0530 (India Standard Time)
The millisecond information is not present. I however need that in a date type that Java webservice also considers as Date and not string. I read about momentjs format approach but that basically returns a string and not date.
What I need is like: Thu Sep 07 2017 15:10:46:955GMT+0530 (India Standard Time).
ECMAScript Dates are based on a time value that is milliseconds since 1970-01-01T00:00:00Z, so they are inherently UTC. Therefore the value returned by:
new Date().getTime();
// or more concisely
Date.now();
does not need a timezone and includes millisecond precision. You can also use toISOString which returns an ISO 8601 extended date with milliseconds, again using UTC, e.g. 2017-09-07T22:51:51.287Z.
The ISO format is very widely accepted, is conveniently human readable and is unambiguous.
However, if it's important to also convey the timezone of the source, you can use the timezone offset (which is returned in minutes to add to local time to get UTC) and format it to something more standard.
function getISOOffset(date) {
date = date || new Date();
function z(n){return ('0'+n).slice(-2)}
var offset = date.getTimezoneOffset();
// ECMScript offset sign is the reverse of ISO 8601
var sign = offset < 0? '+' : '-';
offset = Math.abs(offset);
return sign + z(offset/60 | 0) + ':' + z(offset % 60);
}
console.log('The host offset is UTC' + getISOOffset())
If you are ok with purely milliseconds you can use something like this:
Date.now(); // 1504785573971
This works on almost all modern browsers. It doesn't tell you the timezone of the user, but does give you a consistent number against which to compare (milliseconds since Midnight of January 1, 1970, GMT).
For the very specific timestamp you seek, you might need a library like moment.js - it's a pretty heavy solution, but gives you excellent control over formatting.
Moment.js Formatting Options
This will be a string as there is not truly agreed-upon formation for passing dates in JSON. It will require parsing logic in the Java. I don't have much experience on the Java side, but I believe the popular libraries like Jackson and GSON support this conversion.
If you are not using JSON to submit information to the server, normal form submissions are passed as a string and have to be parsed out on the server, anyway.

How to transform a JavaScript Date to a different timezone

If I run var myDate = new Date('29-06-2016 10:00'), myDate will only contain one thing: a number. The number of milliseconds from 01-01-1970 00:00:00 GMT to 29-06-2016 10:00:00 XXX
XXX being the timezone of the OS. In my case BST (because it is a summer date, in winter would be GMT).
Now... What if I want the milliseconds from 01-01-1970... to 29-06-2016 10:00:00 GMT-7?
I only found methods to tell me what time is in the GMT-7 timezone when in BST timezone is 29-06-2016 10:00:00, but that is not what I am looking for!
Also, to change an environmental variable so the timezone is GMT-7 is not an option.
I think you want the date string in the following format
"2016-06-29T10:00:00-07:00"
That lets you set the timezone relative GMT (not 100% sure on the timezone, but it's client side so does depend on their locale).
I had a similar thing where JS was changing the time on date objects and the only way I found was to set up the date and set this.
Bonus info, to get this from a .NET DateTime using the following string format.
"yyyy-MM-ddTHH:mm:sszzz"
I think I found a way of doing it, using moment.js as ErikS suggested:
// This code is running in a Node.js server configured to use UTC
// Incorrect date, as it is interpret as UTC.
// However, we do this to get the utcOffset
var auxDate = moment.tz(new Date('2016-6-23 10:15:0'), 'US/Mountain');
// Get the milliseconds since 1970 of the date as if it were interpreted
// as GMT-7 or GMT-6 (depends on the date because of Daylight Saving Time)
var milliseconds = auxDate.valueOf() - auxDate.utcOffset() * 60000;

moment.js does not convert timestamps with specific timezones to unix timestamps

I am using moment.js to convert a bunch of timestamps in it's specific timezone to a unix timestamp like this:
var timestamp = "2015-12-29T09:35:00.000-08:00";
console.log(moment("2015-12-29T09:35:00.000-08:00").unix();
console.log(moment("2015-12-29T09:35:00.000-08:00").tz("America/Los_Angeles").unix();
The console log of both the above statements is for some reason, the same - 1451361900. This unix timestamp which it is logging is in my local timezone and not the one I asked for: "America/Los_Angeles". What am I missing?
A unix timestamp, or Posix, should always be in the UTC (Coordinated Universal Time) format.
Moment is just doing something like
function unix () {
return Math.floor(+this / 1000);
}
Where it converts the date object to an integer and then converts from milliseconds to seconds.
The starting point is a regular javascript Date object, and the ECMA standard says
Date objects are based on a time value that is the number of
milliseconds since 1 January, 1970 UTC.
so date objects are always UTC when converted to the number of milliseconds since 1. January 1970 (epoch), i.e. you can't set another timezone on a Unix timestamp, both your dates are the same.
The proper way is to use moment-Timezone is this.
console.log(moment("2015-12-29T09:35:00").unix());
console.log(moment.tz("2015-12-29T09:35" , "America/Los_Angeles").unix());
In above your are providing time zone as a string too which is this last part ".000-08:00" and then you are providing another zone, which is incorrect.
As you are trying to find out the unix timestamp for the date "2015-12-29T09:35:00.000-08:00". In this date format timezone value is already present which is "-08:00", hence you get the same unix timestamp.
For getting the unix timestamp desired solution, remove the timezone value and use moment-timezone as :
console.log(moment.tz("2013-12-01", "America/Los_Angeles").unix());
For more details check moment-timezone

Categories

Resources