Date parsed with gmt + 2 hours - javascript

I always get the wrong date when I use var date = new Date(timestring), there is always +2 GMT hours.
var unsortedPlayTimes =
[{date:'2014-08-11T09:30:00'},
{date:'2014-08-11T08:30:00'},
{date:'2014-08-11T08:15:00'},
{date:'2014-08-11T08:45:00'},
{date:'2014-08-11T12:30:00'},
{date:'2014-08-11T10:30:00'},
{date:'2014-08-11T11:30:00'},
{date:'2014-08-11T07:30:00'},
{date:'2014-08-11T13:00:00'},
{date:'2014-08-11T23:00:00'},
{date:'2014-08-12T00:00:00'},
{date:'2014-08-12T01:00:00'},
{date:'2014-08-12T05:00:00'},
{date:'2014-08-12T09:00:00'},
{date:'2014-08-11T14:00:00'},
{date:'2014-08-11T18:30:00'},
{date:'2014-08-11T13:00:00'}];
function SortandFilterPlayTimes (allPlayTimes) {
var filteredPlayTimes = [];
$.each(allPlayTimes, function(index, value) {
var date = new Date(value.date);
if ($.inArray(date,filteredPlayTimes) === -1) {
filteredPlayTimes.push(date);
}
});
};
Why is JavaScript always adding this +2 hours ?

You're using the ISO-8601 formatting of dates while omitting the timezone, this makes the parsing consider the timezone as UTC in ES5 (this will be different in ES6 : strings in ISO format will be considered as local too when the timezone isn't provided).
If you want the date to be parsed with your local timezone in ES5, you might change the format to a not ISO one :
var date = new Date(value.date.replace(/T/,' '));
But you might also want to check you really want the date to be parsed depending on the user's timezone, this is most often a bad idea. The usual good solution is to send the timezone or to send the date as a unix timestamp (what you get with date.getTime()).

You are parsing ISO-8601 timestamps without timezone information, thus a UTC timezone is assumed, but Date.prototype.toString() will provide a string representation of this timestamp in your current timezone which means that if you are in the UTC+2 timezone you will notice a shift by two hours.

I'm guessing your project is hosted on a server that has a +2 hours time difference with your local system, thus giving you a time you are not expecting. Is your server in a different country?

Related

How to format a string in UTC to the configured timezone on Moment

I have the following string, which is in UTC:
2022-02-01T00:00:00Z
I have already configured my timezone, so I do not want to mess/call .tz()
I know that this string is in UTC, but I am not managing to convert from UTC to the defined timezone, which in this example is pacific/wallis.
I have tried many things, as
const utc = moment.utc('2022-02-01T00:00:00Z').toDate()
const inConfiguredTimeZone = utc.format()
My desire is to get this timestamp 2022-02-01T00:00:00Z and have converted to the defined timezone on Moment
I need to tell moment that "This string is in UTC, please give me the converted timestamp in the defined time zone"
If you just want to format a UTC timestamp in your current timezone (determined by your computer's time settings) just use
let s = moment("2022-02-01T00:00:00Z").format();
This will produce a string like 2022-02-01T12:00:00+12:00 if you are currently in a timezone that has a UTC offset of +12 hours (like pacific/wallis) or 2022-02-01T01:00:00+01:00 if you are currently in a timezone that has a UTC offset of +1 hours (like europe/berlin)
If you want it converted to a specific timezone use
let s = moment("2022-02-01T00:00:00Z").tz("pacific/wallis").format();
This will produce 2022-02-01T12:00:00+12:00, regardless of your current timezone.

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

How to convert GMT time to user's Local time Javascript

I'm trying to convert a GMT time to the user's Local time.
the format of the time i'm getting from the server is : 2015-05-20 18:00:00 GMT
I just want to show hours and minutes like that : 20:00
I wanted to use this solution which seems pretty easy, but I don't know how to make my format same as this
var date = new Date('5/21/2015 18:52:48');
date.toString();
the format of the time i'm getting from the server is : 2015-05-20 18:00:00 GMT
If so, you can easily massage that into a format that ES5 and higher browsers are supposed to support, which would be 2015-05-20T18:00:00Z for your example:
var yourString = "2015-05-20 18:00:00";
var dt = new Date(yourString.replace(' ', 'T') + "Z");
var hours = dt.getHours(); // Will be local time
var minutes = dt.getMinutes(); // Will be local time
Then just format the hours and minutes values you get into your desired hh:mm string.
Note: The Z at the end of the string is important. Unfortunately, the ES5 specification has a significant error in it (they're fixing it in ES6) around what the engine should do if there is no timezone on the string being parsed. Some engines do what the spec says, others do what the spec should have said (and the ES6 spec will say), which unfortunately means that right now, you can't trust what browsers will do if there's no timezone on the string.
I just had to add " UTC "
var date = new Date('2015-05-20 15:00:00 UTC');
alert(date.getHours());
alert(date.getMinutes());
new Date() in browser returns date object in user's timezone(machine timezone).
Just you need to pass GMT date to Date function in ISO format. So it will treat it as gmt time.
var date = new Date('2015-05-21T18:52:48Z');
date.toString();//You will get here date string in local format
You can also use UTC as UTC and GMT are same.
Here is ex.
var date = new Date('2015-05-21 18:52:48UTC'); //You can use GMT instead UTC
date.toString();//You will get here date string in local format
First method is preferable as second method doesn't work on Internet Explorer

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

How do you check whether a date is UTC in Javascript?

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;

Categories

Resources