Reversing epoch time conversion - javascript

Im using moment.js to convert a long/epoch time in to a humane readable format:
function convertValue(x) {
var mytime = x; // x = 1460554200000000
mytime = moment.utc(mytime).utcOffset(moment().format('ZZ'));
mytime = mytime.format('DD-MM-YY HH:mm:ss.SSS');
mytime = mytime + ' (' + moment().format('[UTC]ZZ') + ')';
return myTime;
}
Which myTime would return something like: 14-05-16 15:55:05.000 (UTC+100)
How can i do the opposite, so, if i was to receive something like: 29-01-16 14:35:05.000 (UTC+100) and convert back to an epoch time?

For a given moment object, if you want the result as a string:
Use .format('x') for the timestamp in milliseconds
Use .format('X') for the timestamp in seconds
However, if you want the result as a number:
Use .valueOf() for the timestamp in milliseconds
Use .unix() for the timestamp in seconds
However, with regards to the code you provided:
The offset UTC+100 is nonstandard and somewhat ambiguous. It could be UTC+10, UTC+10:00, UTC+0100, or UTC+01:00.
DD-MM-YY may be confusing to users, as it using two digit years, and is in reverse order of what is usually expected. Use YYYY-MM-DD if you're intending it to be used by a large number of people, or if you're going for something locale specific then make sure you're using separators that are common in the locale. Usually / or .
You're pairing the timestamp given with the current offset, rather than the offset in effect at the given time. That's going to fail in many locations where the time zone offset changes for daylight saving time and other time zone changes.
Your code should just be:
var mytime = moment(x).format('YYYY-MM-DD HH:mm:ss.SSS [UTC]ZZ');
To create a moment object from a string in a particular format, simply provide that format when parsing. So, the reverse function would be:
var x = moment(mytime, 'YYYY-MM-DD HH:mm:ss.SSS [UTC]ZZ').valueOf();

As long as you can coerce it back in to a moment object, you should be able to use moment().format('x') to get back to a Unix timestamp.
If you're talking about parsing a non standard date string in to a moment object, that's a lot more difficult. Since you know the format it was output as you should be able to use moment(dateString, formatString) to create a moment out of it.

Related

Same date in all timezones

I have a problem showing the same date in all timezones.
Users input is for example 01-01-2002 and I store it like a date with Eureope/Berlin timezone
parseFromTimeZone(String(birthDate), { timeZone: 'Europe/Berlin' })
and the result of parseFromTimeZone is this string '2001-12-31T23:00:00.000Z'. String date counts with timezone in Berlin that is why it is shifted for one hour.
And I need to get from '2001-12-31T23:00:00.000Z' this 01-01-2002 in all timezones.
I using formatISO(new Date(date), { representation: 'date' })) this returns 01-01-2002 when my timezone is Europe/Prague or Europe/Berlin
but when I change the timezone to America/Tijuana then formatISO returns 2001-12-31 and that is wrong I need to have the same date as is in Europe/Berlin always! Bud for Asia/Tokyo this function returns 01-01-2002 that is right ...
Some ideas? I have tried a lot of solutions but none works for all timezones...
I am using "date-fns": "^2.15.0", "date-fns-timezone": "^0.1.4"
Try this function with an ISO_8601 date, then change the timezone in your computer's settings and try again with the new timezone. It should print the same date on your web page for both time zones.
getDateFromISO(iso_string: string): string | Date {
if (!iso_string)
return null;
const isIsoDate = /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z/.test(iso_string); // check if string is in format 2022-01-01T00:00:00.000Z
const isDateTimeWithoutZone = /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/.test(iso_string); // check if string is in format 2022-01-01T00:00:00
const isDateYMD = /\d{4}-\d{2}-\d{2}/.test(iso_string); // check if string is in format 2022-01-01
if (!isIsoDate && isDateTimeWithoutZone)
iso_string += '.000Z';
else if (!isIsoDate && isDateYMD)
iso_string += 'T00:00:00.000Z';
else if (isIsoDate)
iso_string = iso_string;
else
return iso_string;
const dateFromServer = new Date(iso_string);
const localOffset = new Date().getTimezoneOffset(); // in minutes
const localOffsetMillis = 60 * 1000 * localOffset;
const localDate = new Date(dateFromServer.getTime() + localOffsetMillis);
return localDate;
}
The Date object, despite its name, is does not represent a "date". It represents a timestamp. All that it stores internally is the number of milliseconds since the Unix epoch (which is UTC based). It outputs values based on either UTC or the local time zone of the machine where its running, depending on the function being called.
Thus, if you construct a Date object from a date-only value, you're really taking "the time at midnight" from that time zone and adjusting it to UTC. This is demonstrated by your example of 2002-01-01 in Europe/Berlin. Your treating that as 2002-01-01T00:00:00.000+01:00, which indeed has a UTC equivalent of 2001-12-31T23:00:00.000Z, and thus doesn't carry the same year, month, and day elements as the intended time zone.
You really only have two options to deal with date-only values if you want to prevent them from shifting:
Your first option is to use the Date object, but treat the input as UTC and only use the UTC-based functions. For example:
var dt = new Date(Date.UTC(2002, 0, 1)); // "2002-01-01T00:00:00.000Z"
var y = dt.getUTCFullYear(); // 2002
var m = dt.getUTCMonth() + 1; // 1
var d = dt.getUTCDate(); // 1
var dtString = d.toISOString().substring(0, 10) // "2002-01-01"
If you need to parse a date string, be aware that current ECMAScript spec treats date-only values as UTC (which is what you want), but in the past such behavior was undefined. Thus some browsers might create a local-time result from new Date('2002-01-01'). You may want to explicitly add the time and Z, as in new Date('2002-01-01' + 'T00:00:00.000Z') to be on the safe side.
If you intend to use date-fns, be careful - the parseISO and formatISO functions use local time, not UTC.
The second option is to not use the Date object. Keep the dates in their string form (in ISO 8601 yyyy-mm-dd format), or keep them in a different object of either your own construction or from a library.
The ECMAScript TC39 Temporal proposal is intended to fix such deficiencies in JavaScript. In particular, the Temporal.Date object (preliminary name) will be able to be used for date-only values without having the shifting problem you and so many others have encountered. The proposal is currently in Stage 2 of the ECMAScript process, so it's not available to use today, but this problem will be solved eventually!

Return date and time in ("YYYY-MM-DD HH:mm") format when using moment.js (timezone)

I am using moment-timezone so I can convert from selected timezone to timezone of a client.
I wasn't able to implement it in a better way than this:
convertSelectedTimeZoneToClients() {
let timeZoneInfo = {
usersTimeZone: this.$rootScope.mtz.tz.guess(),
utcOffset: this.formData.timeZone.offset,
selectedDateTime: this.toJSONLocal(this.formData.sessionDate) + " " + this.formData.sessionTime
};
let utcTime = this.$rootScope.mtz.utc(timeZoneInfo.selectedDateTime).utcOffset(timeZoneInfo.utcOffset).format("YYYY-MM-DD HH:mm");
let convertedTime = this.$rootScope.mtz.tz(utcTime, timeZoneInfo.usersTimeZone).format("Z");
return convertedTime;
}
So basically I am using usersTimeZone: this.$rootScope.mtz.tz.guess(), guess() function to find out timezone from the browser.
Then I get values from datetime picker and dropdown and convert them to UTC value by using utcOffset.
At the end I want to convert that utc value to user timezone value.
I get object like this:
_d represent correct value after conversion. I have tried adding bunch of different .format() paterns on convertedTime variable, but I am not able to retrive time in this format: "YYYY-MM-DD HH:mm". I guess it works differentlly than when using .utcOffset() function.
Can anybody help me with this?
You don't need to guess the client time zone to convert to local time. Just use the local function.
For example:
moment.tz('2016-01-01 00:00', 'America/New_York').local().format('YYYY-MM-DD HH:mm')
For users located in the Pacific time zone, this converts from Eastern to Pacific and you get an output string of "2015-12-31 21:00". For users in other time zones, the output would be different, as expected.
You don't need to format to a string and re-parse it, or manually manipulate the UTC offset either. That is almost never warranted.

Strip Time Zone from a string using JavaScripty, Moment.js, etc?

Suppose I have a string like "01/22/2014 2:07:00 PM -08:00".
I want to
a) Format it in ISO 8601 with time offsets from UTC http://goo.gl/JTfAZq, so it becomes "2014-01-22T14:07:00-08:00"
b) Strip out time offset part so it becomes "01/22/2014 2:07:00 PM" [and then format it in ISO 8601 so it becomes "2014-01-22T14:07:00"]
Sure I can use JavaScript string functions (and regular expressions), but it seems to be a better approach to use JavaScript Date() object facilities or Moment.js. Neither work, however. Both automatically convert dates to a current system timezone (-05:00 for me), so 2:07 PM becomes 5:07 PM. I found two ways of doing that "strip out time offset then format" task, but both looks ugly and brittle:
var mydateTime = "01/22/2014 2:07:00 PM -08:00";
// strip out time offset part using substring() so that Moment.js
// would think time is specified in a current zone
var myNewDateTime1 = moment(mydateTime.substring(0, mydateTime.length - 7)).format("YYYY-MM-DDTHH:mm:ss")
// or probably even worse trick - strip out time offset part using format
var myNewDateTime2 = moment(mydateTime, "MM/DD/YYYY h:mm:ss A").format("YYYY-MM-DDTHH:mm:ss")
I understand that JavaScript Date() object is not designed to preserve a time zone, but doesn't more elegant and stable solution exist for a) and b) ?
I think you are looking for moment.ParseZone. It parses the moment AND preserves the time zone offset that was in the string, instead of converting it to the browser's local time zone.
Also, your myDateTime variable doesn't match what you were asking about. If you do indeed already have a full ISO8601 extended with time zone offfset, then it is like this:
var m = moment.parseZone("2014-01-22T14:07:00-08:00");
Or if it's like you originally, showed, then like this:
var m = moment("01/22/2014 2:07:00 PM -08:00",
"MM/DD/YYYY h:mm:ss A Z").parseZone();
From there, you can format it however you like:
var s = m.format("YYYY-MM-DDTHH:mm:ss");

How do you preserve a JavaScript date's time zone from browser to server, and back?

For example, using a date and time control, the user selects a date and time, such that the string representation is the following:
"6-25-2012 12:00:00 PM"
It so happens that this user is in the EST time zone. The string is passed to the server, which translates it into a .NET DateTime object, and then stores it in SQL Server in a datetime column.
When the date is returned later to the browser, it needs to be converted back into a date, however when the above string is fed into a date it is losing 4 hours of time. I believe this is because when not specifying a timezone while creating a JavaScript date, it defaults to local time, and since EST is -400 from GMT, it subtracts 4 hours from 12pm, even though that 12pm was meant to be specified as EST when the user selected it on a machine in the EST time zone.
Clearly something needs to be added to the original datetime string before its passed to the server to be persisted. What is the recommended way of doing this?
Don't rely on JavaScript's Date constructor to parse a string. The behavior and supported formats vary wildly per browser and locale. Here are just some of the default behaviors if you use the Date object directly.
If you must come from a string, try using a standardized format such as ISO8601. The date you gave in that format would be "2012-06-25T12:00:00". The easiest way to work with these in JavaScript is with moment.js.
Also, be careful about what you are actually meaning to represent. Right now, you are passing a local date/time, saving a local/date/time, and returning a local date/time. Along the way, the idea of what is "local" could change.
In many cases, the date/time is intended to represent an exact moment in time. To make that work, you need to convert from the local time entered to UTC on the client. Send UTC to your server, and store it. Later, retrieve UTC and send it back to your client, process it as UTC and convert back to local time. You can do all of this easily with moment.js:
// I'll assume these are the inputs you have. Adjust accordingly.
var dateString = "6-25-2012";
var timeString = "12:00:00 PM";
// Construct a moment in the default local time zone, using a specific format.
var m = moment(dateString + " " + timeString, "M-D-YYYY h:mm:ss A");
// Get the value in UTC as an ISO8601 formatted string
var utc = m.toISOString(); // output: "2012-06-25T19:00:00.000Z"
On the server in .Net:
var dt = DateTime.Parse("2012-06-25T19:00:00.000Z", // from the input variable
CultureInfo.InvariantCulture, // recommended for ISO
DateTimeStyles.RoundtripKind) // honor the Z for UTC kind
Store that in the database. Later retrieve it and send it back:
// when you pull it from your database, set it to UTC kind
var dt = DateTime.SpecifyKind((DateTime)reader["yourfield"], DateTimeKind.Utc);
// send it back in ISO format:
var s = dt.ToString("o"); // "o" is the ISO8601 "round-trip" pattern.
Pass it back to the javascript in moment.js:
// construct a moment:
var m = moment("2012-06-25T19:00:00.000Z"); // use the value from the server
// display it in this user's local time zone, in whatever format you want
var s = m.format("LLL"); // "June 25 2012 12:00 PM"
// or if you need a Date object
var dt = m.toDate();
See - that was easy, and you didn't need to get into anything fancy with time zones.
Here, I think this is what you are looking for:
How to ignore user's time zone and force Date() use specific time zone
It seems to me that you can do something like this:
var date = new Date("6-25-2012 12:00:00 PM");
var offset = date.getTimezoneOffset(); // returns offset from GMT in minutes
// to convert the minutes to milliseconds
offset *= 60000;
// the js primitive value is unix time in milliseconds so this retrieves the
// unix time in milliseconds and adds our offset.
// Now we can put this all back in a date object
date = new Date(date.valueOf() + offset);
// to get back your sting you can maybe now do something like this:
var dateString = date.toLocaleString().replace(/\//g,'-').replace(',','');
Blame the JSON.Stringfy()... and do:
x = (your_date);
x.setHours(x.getHours() - x.getTimezoneOffset() / 60);
I am using a filter before sending the date to the server:
vm.dateFormat = 'yyyy-MM-dd';
dateToSendToServer = $filter('date')(dateFromTheJavaScript, vm.dateFormat);

Convert from string with milliseconds to date object Javascript

I got this problem when dealing with date time conversion. I have timestamp data from postgreSQL database with format like this one
"2011-04-04 19:27:39.92034"
In order to display it in highcharts, I have to convert it to date or time object. Without milliseconds, I easily convert it with Date.js
But milliseconds can't be handled with that library. I tried also with Date.parse but always got NaN.
Any solution for this problem? Thank you
JS built in Date class should be able to handle this, and getTime() can return milliseconds since start 1970 (UNIX time). Watch out for time zone issues though; the constructor may interpret the date/time as being local, but getTime()'s milliseconds since 1970 may be in UTC, baking in a conversion that is difficult to remove.
new Date("2011-04-04 19:27:39.92034").getTime()
1301941659920
Many ways to Rome. The given code will return '(datestr=) 2011-4-4 19:27:39.92'. Is that what you look for?
var darr = '2011-04-04 19:27:39.92034'.split('.')
, dat=new Date(darr[0])
, datestr = '';
dat.setMilliseconds(Math.round(darr[1]/1000));
datestr = [ [dat.getFullYear(),dat.getMonth()+1,dat.getDate()].join('-')
,' ',
[dat.getHours(),dat.getMinutes(),dat.getSeconds()].join(':')
,'.',
dat.getMilliseconds()
].join('');
Can't you just cut of the last 6 chars of that string? You might then round the miliseconds and eventually add a second to you time object.
This is simpler and in one line:
new Date('01/09/2015 06:16:14.123'.split(".")[0])

Categories

Resources