Convert date with timezone to UTC? - javascript

A quick question. I have a ISO string date:
2022-07-03T10:51:09+02:00
this date as you can see has timezone included (+02:00).
Question: How to convert it into UTC date? Using e.g. date-fns or moment?
Edit: Should I just simply add "02:00" hours to current date? So it would be 12:51:09?

Trivially new Date(isoString).toISOString(), no libraries required.
const input = "2022-07-03T10:51:09+02:00";
console.log(`${input} in UTC:\n${new Date(input).toISOString()}`);

In my view, timezone is simply the representation of the same timestamp across different geographies (no. of seconds elapsed since unix time 0 is the same everywhere). So be careful while adding/removing time manually from the existing timestamp.
You can do that using moment.js like this:
var someday = moment('2022-07-03T10:51:09+02:00');
console.log(someday.utc().format());
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment-with-locales.min.js"></script>

Related

How to make Moment.js ignore the user's timezone?

I've got a form where I input an event that starts at a certain time. Let's say 9am.
To assign a date/time object I'm using MomentJs. The issue comes when displaying it in different time-zones.
In London will show up 9am as intended - in Kiev will show 11am.
How can I make MomentJS and the browser ignore which timezone is relevant for the user, and just displaying the time I'm giving?
Here's my code:
<p>
Start time:
{moment(event.startDate).format("HH:mm")}
</p>
Assuming you have stored the date as utc (which in this case you probably should have), you could use the following:
moment.utc(event.startDate).format("HH:mm")
Let me provide an alternative answer in Vanilla JavaScript. If you want to make it timezone 'neutral', you can first convert it to UTC using toISOString().
const current = new Date();
const utcCurrent = current.toISOString();
console.log(utcCurrent);
If you want to convert it to a specific timezone, such as London, you can use toLocaleString(). Do take note of the browser support for the timezone though.
const londonTime = new Date().toLocaleString('en-US', { timeZone: 'Europe/London' })
console.log(londonTime);
What you want is a normalized Datetime. This can get a little confusing since the concept of timezones is a rather arbitrary construct.
I like to think of Datetime values as "absolute" and "relative". An "absolute" Datetime is one that is true regardless of which timezone you're in. The most common example of these are UTC(+000) and UNIX Time (also known as Unix epoch, POSIX Time or Unix Timestampe).
UTC is pretty obvious. Its the current time at +000 timezone. UNIX time is a bit more interesting. It represents the number of seconds that have elapsed since January 1, 1970.
You should always store data, in both client and backend, as an "absolute" time. My preference is UNIX time since its represented as a single integer (nice and clean).
moment.js does this for you. When you instantiate your moment object, you can use:
var date = moment.utc(utcString)
or for Unix Time
var date = moment.unix(unixInt)
You can then use this object to display the date in any form you wish:
console.log(date.tz.("America/Toronto"))
The only way I could solve this is by removing the timezone and milliseconds info from the string. I used date-fns lib but I imagine moment will work the same way.
import { format } from 'date-fns'
const myDateTimeString = '2022-02-22T19:55:00.000+01:00'
const dateTimeWithoutTimezone = myDateTimeString.slice(0, 16) // <- 2022-02-22T19:55
format(new Date(dateTimeWithoutTimezone), 'HH:mm')

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

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

Moment.js round dates up

In my javascript the library Moment.js rounds my dates up.
Date: 2015-02-09T23:00:00.000Z
moment(Date).format('DD/MM'); ==> Becomes 10/02
I want 09/02 as result. Is there a possible way that the library not rounds the date?
The problem is likely one of timezones: by default, momentjs parses your string and converts it to your local timezone. If I see this correctly, the 'Z' in your date signifies zulu - or UTC time. If your timezone is +02:00 for example, that would make it the 10th, 01:00.
Use Moment#utc
moment(Date).utc().format('DD/MM');
to output format the date as UTC again.
Moment.js will output dates in the local time zone, so it might very well be that it's caused by a difference in timezones.
If you want to show the date/time as encoded into the original string, use parseZone like this:
var dateStr = "2015-02-09T23:00:00.000Z";
moment.parseZone(dateStr).format('DD/MM');
You can try like below.
moment(Date,['YYYY-MM-DD']).format('DD/MM');

How to convert 2014-04-23T19:45:39 (UTC date) to AST date

I have a date like this:
2014-04-23T19:45:39 which is a UTC format.
I want to convert it to AST format or the localize time zone of the user. How to do it?
I suggest you use moment.js library and just add or subtract number of hours that AST time have comparing to UTC.
new_date = date.add('hours',4);
or
new_date = date.subtract('hours',4);
using timezone-js. you can easily convert the time from one timeZone to another. timezone.js
var date_object;
function localize(t){
date_object=new Date(t+" UTC");
document.write(date_object.toString());
}
localize("4/24/2014 4:52:48 PM")
document.write(date_object.toString().replace(/GMT.*/g,""));
Demo

Categories

Resources