I have a filter that i use to convert date to UTC date.
.filter('utc', function(){
return function(val){
var date = new Date(val);
return new Date(date.getUTCFullYear(),
date.getUTCMonth(),
date.getUTCDate(),
date.getUTCHours(),
date.getUTCMinutes(),
date.getUTCSeconds(),date.getTimezoneOffset());
};
})
So when i give the date 2016-06-18
It returns the date like this Sat Jun 18 2016 00:00:00 GMT-0400 (Eastern Daylight Time)
The date is correct but its not reflecting the correct timezone.
I want it to return in UTC timezone, like Z at the end
A few things:
The Date constructor does not have a parameter that accepts a time zone offset. The parameter following seconds is milliseconds. Refer to the MDN reference.
You should not pass UTC-based values into the Date constructor where local-based values are expected. Doing so will have the effect of tracking a completely different point in time. You may think you're adjusting for time zone offset, but you are not.
The Date object always has the following behaviors:
It tracks a single value, as returned by .valueOf() (inherited from Object.valueOf), or by .getTime(). That value is the number of milliseconds elapsed since Midnight at the start of Jan 1, 1970, in UTC (ignoring leap seconds).
The vast majority of input and output functions work with the local time zone - that is, the time zone that is set by the computer where the code is running. The functions that work with UTC typically have "UTC" in their name.
It is not possible to get the Date object to use a different time zone. Any solution that claims otherwise is not considering edge cases. In particular, "epoch-shifting" is a common approach that is fundamentally wrong, when used in isolation. (Passing UTC values into local-time parameters is one implementation of epoch shifting.)
If you're looking for a quick solution, consider .toUTCString() or .toISOString().
Some browsers may also support the ECMAScript Internationalization API and let you do: .toLocaleString(undefined, { timeZone: 'UTC'})
Moment.js is a very common library for dealing with these sorts of issue, and fills in a lot of gaps that the Date object has. Local-to-UTC is done like this:
moment(input, inputFormat).utc().format(outputFormat)
Note that moment does a lot of its magic via epoch-shifting, but it hides this via a public API and new object type (a moment object), which provides a layer of safety that you just can't get with the Date object alone.
Note that in your question you did not at all state what was in the val variable. Depending on whether that is a number, or a string, and what format that string is in, the parsing behavior of the Date object may change considerably.
You can use Date.prototype.toISOString() for this.
You can modify your function to return
return new Date(date.getUTCFullYear(),
date.getUTCMonth(),
date.getUTCDate(),
date.getUTCHours(),
date.getUTCMinutes(),
date.getUTCSeconds(),date.getTimezoneOffset()).toISOString();
Related
I need to convert a local timezone to Pacific/Los angeles.
Example, if user in Hawaii
Code: taken here from https://stackoverflow.com/a/54127122/15358601
function convertTZ(date, tzString) {
return new Date((typeof date === "string" ? New Date(date) : date).toLocaleString("en-US", {timeZone: tzString}));
}
convertTZ(new Date(), "America/Los_Angeles")
Sun Mar 14 2021 17:01:59 GMT-1000 (Hawaii-Aleutian Standard Time) {}
It still prints the final with Hawaii. I need America/Los Angeles Display, not Hawaii. (however it still prints the correct new Hours and Minutes, just the Display label is incorrect)
How can this be done?
The solution should work for other timezones also, printing it respectively its other timezone, eg: America/New_York, Europe/London, Europe/Paris, etc ,
A few things:
The approach in the answer you linked to for the convertTZ is flawed. One should not parse the output of toLocalString with the Date constructor. Please read the comments following that answer.
The Date object can not be converted to another time zone, because it is not actually in any time zone. The only thing encapsulated by the Date object is its Unix timestamp, which can be seen with .valueOf(), .getTime(), or any mechanism that coerces it to a Number. Such values are always UTC-based.
When you see local time or a time zone coming from the Date object, the system's local time zone is applied to the internal UTC-based Unix Timestamp to create the output. The local time zone cannot be changed programmatically from JavaScript (or TypeScript), nor can it be altered on a per-object basis.
Instead of trying to convert a Date object in one time zone to a Date object in another time zone, recognize that all Date objects are inherently UTC. Thus, you can create a string that is in a different time zone, (for example, using toLocaleString with the timeZone option) but you cannot create a new Date object from that string. If you want an object that can actually be set to a different time zone, consider Luxon. If you need a solution without a library, you will one day be able to use a ZonedDateTime from the TC39 Temporal Proposal, which will eventually be part of ECMAScript.
Beware of calling console.log on a Date object. Neither the ECMAScript spec nor the WhatWG Console spec defines the behavior of such a call. It is undefined behavior. In some environments, the string output logged is the same as calling .toString() on the Date object - which will give the local time equivalent of the Date object's timestamp, along with a display name for the local time zone. Other environments will show the same output of calling .toISOString(), which will give an ISO-8601 representation of the timestamp in UTC. Instead of logging Date objects, call one of those two functions yourself and log the output.
function convertTZ() {
return new Date().toLocaleString('en-US', { timeZone: "America/Los_Angeles" });
}
console.log(convertTZ());
//Second way
//Hoepfully that's going to be the code that you need.You can change the way that you want to see the date.
function convertTZ() {
return new Date().toLocaleString('en-US', {
timeZone: "America/Los_Angeles" ,
day: "numeric",
month: "short",
year: "numeric",
hour: "numeric",
minute: "2-digit"
});
}
console.log(convertTZ(),' America/Los Angeles');
As per your requirement,
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/resolvedOptions
will help to achieve it.
My local time zone is IST , i tried to define timezone inside Date object like
const usaRegionTime = new Date(inputDate.toString()).toLocaleString(
'en-US',
{
timeZone: 'America/New_York',
}
);
const estDate = new Date(usaRegionTime);
console.log(estDate.getTime());// Uses IST(local time Zone) instead of EST(Specifed time zone)
Example:
My IST time is 7:15 PM and i use the Date object with EST timeZone i get correct EST as 9:45 AM but when i try est.getTime() UTC is calculated as 7:15 pm instead of 1:45 pm . Its taking 9:45 am as IST(Local time Zone) before converting to UTC(Epoch).
Problem is its Taking Browser local timeZone(IST) instead of TimeZone(EST) i gave as param to Date object to get Epoch value . Is there a way to override the Local time Zone with Specified TimeZone while getting Epoch value.
Is there a way to override the Local time Zone with Specified TimeZone while getting Epoch value.
No. You can generate a timestamp for any supported IANA representative location, but you can't "set a timezone" for the Date instance itself.
ECMAScript Date objects are just a time value that is an offset in milliseconds from 1 Jan 1970 UTC. They have no timezone and can only work in either the local timezone or UTC, that's it. When parsing a timestamp for a particular timezone, the result is a UTC time value. That is the only thing the Date instance remembers so it doesn't matter how you generate a Date, the time value is always effectively UTC.
The plain get and set methods like getYear, getMintues, etc. and the toString methods use the UTC time value and host settings to generate local date and time values. The UTC get and set methods like getUTCYear, getUTCMintues, etc. and toISOString, toUTCString etc. return UTC values. So you can work in either local or UTC, working in some other timezone or location requires you to do the work (which is quite complex and likely a library is a better option).
You can get a timestamp for any supported IANA representative location using toLocaleString with the timeZone option, however that only affects the generated string, it doesn't change the underlying UTC time value.
You can't set a timezone or location for a Date object as it doesn't have any property on which to set it, it's just a (UTC) time value, that's it.
Also, the built–in parser is not required to parse the output from toLocaleString, primarily because the user can configure the output to a huge number of different formats that may not include any date or time values (e.g. you can get just the timezone or offset). So depending on parsing such values is fundamentally flawed.
var date= new Date().valueOf(); //gives UTC timestamp in millisecond
const usaRegionTime = new Date(date).toLocaleString(
'en-US',
{
timeZone: 'America/New_York',
}
);
const estDate = new Date(usaRegionTime).toString();
console.log(estDate);
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();
I have dates stored in my database in UTC format and calling
element.createdDate = new Date(element.createdDate.toString());
results in displaying the wrong date.
calling
element.createdDate = new Date(element.createdDate.toUTCString());
returns nothing. How do I go about displaying the correct time from UTC?
It appears that your json response contains a string valued which are in ISO8601 format in UTC, and then you are creating Date objects from them.
This part of your code is fine:
if (element.createdDate) element.createdDate = new Date(element.createdDate.toString());
You parse the string, and the resulting Date object is correct.
However, you don't need to use .toString() here, as the value is already a string. That is redundant.
This part of your code is the problem:
console.log("javascript date: " + new Date(element.depositDate.getUTCDate().toString()));
The getUTCDate function returns just the date of the month. Don't use that.
No matter what you do to create the Date object, ultimately you create a Date object and you're relying upon an implicit string conversion to output it. This will have different behavior in different browsers.
Consider console.log(new Date()):
In Chrome, this logs something like Fri Mar 17 2017 12:14:29 GMT-0700 (Pacific Daylight Time) on my computer. This is as if I called console.log(new Date().toString()); It is in an RFC 2822 like format (but not quite), and is represented in local time.
In Firefox, this logs something like 2017-03-17T19:14:46.535Z. This is as if I called console.log(new Date().toISOString()); It is in ISO8601 format, and is represented in UTC.
The point is, don't rely on implicit undefined behavior. If you must work with Date objects, then you should use console.log(element.createdDate.toISOString()) to see the ISO8601 representation of the UTC time.
If you're going to be doing a lot of things with dates and times, you may prefer to use a library, such as Moment.js, which can make tasks such as this more clear.
I have dates stored in my database in UTC format and calling
element.createdDate = new Date(element.createdDate.toString());
results in displaying the wrong date.
2016-10-11T00:00:00Z and Mon Oct 10 2016 20:00:00 GMT-04:00 (EDT) are exactly the same moment in time. The only difference is that one is displayed in ISO 8601 extended format with timezone offset 00:00 and the other is displayed in an RFC 2822 (like) format with timezone offset -04:00 (and assumes a locality in the EDT region).
calling
element.createdDate = new Date(element.createdDate.toUTCString());
returns nothing.
That is unusual. Typically it would return either a string or an error, but without a working example or any code to provide context it's impossible to say why.
How do I go about displaying the correct time from UTC?
You haven't specified what "correct" is. You are displaying a date and time for the same moment in time, just in a different format and time zone.
I've read this question:
How do you convert a JavaScript date to UTC?
and based on this I implemented this conversion in a dateTools module as follows:
[Update]
var dt, utcTime;
dt = new Date();
utcTime = new Date(Date.UTC(dt.getFullYear(),
dt.getMonth(),
dt.getDate(),
dt.getHours(),
dt.getMinutes(),
dt.getSeconds(),
dt.getMilliseconds()));
Now I'd like to write unit tests. My idea was to check whether the result is actually in UTC, but I don't know how.
All the toString, toUTCString and similar methods seem to be identical for the input (non UTC) and output (UTC) date.
Only the result of the getTime method differs.
Is there a way to check wheter a date is UTC in javascript? If not, is there a better idea to unit test this?
To give more context:
Only converting the it to a UTC string is not that helpful, because in the next step the date is sent to an Asp.net service and therefore converted to a string like:
'/Date([time])/'
with this code
var aspDate = '/Date(' + date.getTime() + ')/';
var aspDate = '/Date(' + date.getTime() + ')/';
This outputs the internal UNIX epoch value (UTC), which represents a timestamp. You can use the various toString methods to get a more verbose string representation of that timestamp:
.toString() uses the users timezone, result is something like "Fri Jan 25 2013 15:20:14 GMT+0100" (for me, at least, you might live in a different timezone)
.toUTCString() uses UTC, and the result will look like "Fri, 25 Jan 2013 14:20:15 GMT"
.toISOString() uses UTC, and formats the datestring according to ISO: "2013-01-25T14:20:20.061Z"
So how do we construct the time value that we want?
new Date() or Date.now() result in the current datetime. No matter what the user's timezone is, the timestamp is just the current moment.
new Date(year, month, …) uses the users timezone for constructing a timestamp from the single values. If you expect this to be the same across your user community, you are screwed. Even when not using time values but only dates it can lead to odd off-by-one errors.
You can use the setYear, setMonth, … and getYear, getMonth … methods to set/get single values on existing dates according to the users timezone. This is appropriate for input from/output to the user.
getTimezoneOffset() allows you to query the timezone that will be used for all these
new Date(timestring) and Date.parse cannot be trusted. If you feed them a string without explicit timezone denotation, the UA can act random. And if you want to feed a string with a proper format, you will be able to find a browser that does not accept it (old IEs, especially).
Date.UTC(year, month, …) allows you to construct a timestamp from values in the UTC timezone. This comes in handy for input/output of UTC strings.
Every get/set method has a UTC equivalent which you can also use for these things.
You can see now that your approach to get the user-timezone values and use them as if they were in UTC must be flawed. It means either dt or utcTime has the wrong value, although using the wrong output method may let it appear correct.
getTimezoneOffset
Syntax: object.getTimezoneOffset( ) This method
returns the difference in minutes between local time and Greenwich
Mean Time. This value is not a constant, as you might think, because
of the practice of using Daylight Saving Time.
i.e.
var myDate = new Date;
var myUTCDate = new Date(myDate - myDate.getTimezoneOffset() * 60000);
alert(myUTCDate);
note: 60000 is the number of milliseconds in a minute;