Displaying a localized JS Date without timezone adjustment - javascript

My Angular front-end is getting timestamps via REST requests to a server in the same timezone. The server does not store timestamps in UTC.
I want to :
display the date and time in a localized way
keep the exact same time displayed (I don't want any timezone adjustments)
For example:
timestamp string from server : 2017-09-20T17:45:00
I need to display it localized like this:
mercredi 20 septembre 2017 17:45 (french)
Wednesday, September 20th, 2017 5:45 PM (english)
On 2 different machines, I get different results, even though the OS is configured with the same timezone :
(UTC+01:00) Brussels, Copenhagen, Madrid, Paris
On machine 1:
Wednesday, September 20th, 2017 6:45 PM // (english) KO !!
On machine 2:
Wednesday, September 20th, 2017 5:45 PM // (english) OK
Currently, the code is:
jsDate = new Date(dateTimeStr);
localizedDateTime = moment(jsDate).local().format('LLLL');
What would be a safe way to always get 5:45 PM ?
Thanks

You're using moment wrong.
Native javascript Date won't necessarily parse that string properly.
Moment will.
From the moment docs String + Format.
localizedDateTime = moment(dateTimeStr, "YYYY-MM-DDTHH:mm:ss").local().format('LLLL');

Related

Why in javascript, creating date between 1st October 1941 and 14th October 1945 adding GMT+0630 as time zone

My Time Zone is (UTC +05:30)Chennai, Kolkata, Mumbai, New Delhi.
For Example:
var date1 = new Date(1944,04,22,0,0,0);
console.log("date1: " + date1);
// output :
// date1: Mon May 22 1944 00:00:00 GMT+0630 (India Standard Time)
var date2 = new Date(1992,11,28,0,0,0);
console.log("date2: " + date2);
// output :
// date2: Mon Dec 28 1992 00:00:00 GMT+0530 (India Standard Time)
date1 is adding GMT+0630 at the end. But if I will take a date after 1945 then it is fine i.e it adds GMT+0530.
Why one extra hour is getting added in Time zone for dates between 1st October 1941 and 14th October 1945.
When i convert date1 in C# with:
Convert.ToDateTime("1944-05-21T17:30:00.000Z").ToString("dd/MM/yyyy");
It gives me 21/05/1944 instead of 22/05/1944.
How can i get correct Date and Time in C#?
A few things:
Indeed, India did use UTC+6:30 for several periods in the 1940's. This information is recorded in the IANA time zone database. You can also refer to the detail of time in India here.
.NET (when running on Windows) does not use the IANA time zone database, but rather the Microsoft Windows time zone database. You can read about some of the differences between these two data sets in the timezone tag wiki.
The Windows time zone database generally does not have the long term history of most time zones. For India Standard Time, it doesn't have any history - assuming that UTC+5:30 has always been in effect. If your application needs to know about historical time zone information, then you have two options:
If you are using .NET Core, you can run on a non-Windows OS (Linux, MacOS, etc.) which uses the full IANA time zone database. The standard TimeZoneInfo, DateTime, and DateTimeOffset APIs will use this data on non-Windows machines.
You can bring your own copy of the IANA TZDB data via a library such as Noda Time. Then you can run on any OS you want. Of course, you will need to stay updated to get changes to the TZDB.
A Noda Time example for your scenario looks like this:
Instant utcTime = Instant.FromUtc(1944, 5, 21, 17, 30);
DateTimeZone tz = DateTimeZoneProviders.Tzdb["Asia/Kolkata"];
ZonedDateTime zdt = utcTime.InZone(tz);
LocalDateTime ldt = zdt.LocalDateTime;
Console.WriteLine(ldt.ToString("dd/MM/yyyy", CultureInfo.InvariantCulture));
There are, of course, shorter ways to write this - and APIs within NodaTime for parsing, formatting, manipulation, conversion etc. But I think you get the point.

moment.js cannot convert actual month into other format

Right now im using the datetimepicker for bootstrap 4
Everything fine so far. I use format LLLL to display the date like this
"moment().format('LLLL'); // Thursday, May 17, 2018 11:57 AM"
This is also working.
Now for saving the data in my MySQL database I want to convert it in the YYYY-MM-DD HH:mm:ss format
The funny thing this is normally working good, but as soon I have date of the the actual month it is not working anymore.
Here is the ouput of my function:
a = Donnerstag, 4. Mai 2017 09:00
Zeit Datenbank ist adb: Invalid date
b = Donnerstag, 13. April 2017 09:00
Zeit Datenbank ist bdb: 2017-04-13 09:00:00
I have two datetimepickers (a & b). Any idea why converting May is not working?
Edit:
January not working
March not working
May not working
December not working
All other months are working!
Code I'm using:
var a=document.getElementById("datetimepicker_start").value;
(to read: a = Donnerstag, 7. Februar 2019 12:53)
var adb = moment(a).format("YYYY-MM-DD HH:mm:ss");
(to convert: Zeit Datenbank ist adb: 2019-02-07 12:53:00)
You need to:
Specify the format of the date you're reading
Include the necessary locale
Using moment without extra args will parse dates based on a limited number of formats, but you can tell it exactly how to parse the given dates by passing an extra argument.
In your case you're reading German, you can include the German locale from here https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.1/locale/de.js.
e.g.
var a = 'Donnerstag, 4. Mai 2017 09:00'
var adb = moment(a, 'LLLL').format("YYYY-MM-DD HH:mm:ss");
console.log(adb);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.1/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.1/locale/de.js"></script>
To be completely explicit, you can also specify the locale when you're reading a date:
moment(a, 'LLLL', 'de');

.NET date, Moment.js, UTC and Timezone shifting

I've got a UTC date through an Ajax call, e.g. "/Date(1517216466000+0100)/",
which is when printing to the console: Mon Jan 29 2018 10:01:06 GMT+0100 (W. Europe Standard Time).
What I need to do, is to let the user change the timezones: I can easily do it with e.g. moment(myDate).tz("Japan").
Then I need to save the date in it's UTC format, which I am not able to do.
I've been experimenting with moment.utc(), but for the input above, it returns 1 hour less.
How to deal with this situation? In summary:
1. Get a UTC time from a webservice
2. Let the user change the timezones
3. Save the modified date in UTC (without the timezone)
Working demo: https://stackblitz.com/edit/angular-kqrct7?file=app%2Fapp.component.html
EDIT for clarification:
Let's just have a look at the hours. What I get the date from the WCF, is 10 o'clock. The browser interprets it as 10 o'clock BUT in GMT+1 so when I convert it to UTC, it becomes 9 o'clock.
I want it to be 10 o'clock as UTC. Then, if I modify the timezone and e.g. the minutes of this date, I want to be able to get the UTC value of this date.
EDIT2: Made my question simplier for clarification
I've got a UTC date, which I get from a webservice like: "/Date(1517216466000+0100)/" which is: Mon Jan 29 2018 10:01:06 GMT+0100 (W. Europe Standard Time) when printed to console.
I add a timezone to it with moment(this.inputDate).tz("Europe/Berlin").format(), but it stays 10:01:06, I guess because of my browsers GMT+1.
I want the ORIGINAL string to be used as a UTC date AND it should remain 10:01:06, not 09:01:06 as you can see above (2nd moment example), so with the timezone "Europe/Berlin" would be 11:01:6
In the .NET JSON formatted date "/Date(1517216466000+0100)/" the timezone offset can be ignored. It represents "2018-01-29T09:01:06.000Z", where the source system was at a timezone offset of +0100. So if you don't care about the source timezone, just ignore it.
It is also an identical moment in time to Mon Jan 29 2018 10:01:06 GMT+0100 (W. Europe Standard Time), just with a different offset.
UTC is not a format, it's a time standard. If you want to use ISO 8601 format:
Extract the first numeric value
Convert to Number
Pass to the Date constructor
Call the toISOString method on the resulting Date
var s = '/Date(-1517216466000+0100)/';
console.log(new Date(+s.replace(/^[^\d-]+(-?\d+).*$/,'$1')).toISOString());
You can also parse and format it using moment.js, which according to the documentation can handle the .NET JSON format without needing to specify the format. So you can either do that or extract the time value and parse it with the "x" format token:
var s = '/Date(1517216466000+0100)/';
// Let moment.js guess the format
console.log(moment(s).utc());
// Extract time value and supply format
console.log(moment(s.replace(/^[^\d-]+(-?\d+).*$/,'$1'), 'x').utc());
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.20.1/moment.min.js"></script>
"/Date(1517216466000+0100)/" is a non-standard way to serialise a date/time. Take a look at ISO8601 which defines several standard ways to represent dates and times.
That being said let's take a look at what this gets evaluated as...
moment("/Date(1517216466000+0100)/").toDate()
gives Mon Jan 29 2018 09:01:06 GMT+0000 (GMT Standard Time) for me (in the UK)
taking just the timestamp value 1517216466000
new Date(1517216466000)
also gives Mon Jan 29 2018 09:01:06 GMT+0000 (GMT Standard Time)
this means that the +0100 is being ignored.
You're not actually modifying the time so why would you expect it to save back as anything other than Mon Jan 29 2018 09:01:06
UPDATE
But the "original" string represents Mon Jan 29 2018 09:01:06 UTC the +0100 is ignored and it's just coincidence that your offset to UTC is also +0100. An off.
Offset and timezone are 2 different things. A timezone encompasses offset to UTC as well as when/if daylight savings comes in to force. Just because it says +0100 doesn't necessarily mean (W. Europe Standard Time) as it could just as easily be (West Africa Time) which is also UTC+0100 but doesn't observe daylight savings at all.
The time you have "/Date(1517216466000+0100)/" doesn't convey enough information to say which timezone it is and JS/moment just uses the timestamp 1517216466000 and as such uses UTC. When you console.log() this the browser writes it to screen as local time Mon Jan 29 2018 10:01:06 GMT+0100 (W. Europe Standard Time) but this is only a representation of the underlying datetime.
By telling moment to use a specific time zone, it's only changing how the date/time gets displayed and doesn't actually change the time it represents.
If you use a date picker to change the date/time then you'll have to serialise the value to send to the backend in an appropriate way that the .Net app you cannot change will understand and conveys what you intend.
Example
Get date from server as var serverTime = "/Date(1517216466000+0100)/"
convert this to a JS Date using moment var time = new moment(serverTime)
Let user specify TimeZone i.e. Japan Standard Time (UTC+9) time = time.tz("Japan")
time still represents Mon Jan 29 2018 09:01:06 UTC but when displayed on screen with time.format() gives "2018-01-29T18:01:06+09:00"
You stated "I want it to be 10 o'clock as UTC". Unfortunately the value you've is NOT 10 O'clock UTC and will never be 10 O'clock UTC because it isn't. It is 9 O'clock UTC
You could parse the value you get from the server yourself but the time from the server IS 9am UTC. If you change it to 10 am UTC then you would see that as Mon Jan 29 2018 11:01:06 GMT+0100 (W. Europe Standard Time) - 11 O'clock local time.
Thanks everyone for your detailed answers, they helped me a lot in understanding my problem! However, the right solution was the following:
10 o'clock was a UTC time in the database and it got interpreted as 9 o'clock UTC in Moment.js because C# handled it as a local time. So, before sending the date to the client, I had to indicate that its a UTC:
var utcToClient = DateTime.SpecifyKind(downtime.DownTimeStartUTC, DateTimeKind.Utc)
Then, in Moment I could create a UTC with:
var jsUtc = moment.utc(downtime.DownTimeStartUTC)
Changing the timezones was a breeze with:
jsUtc.tz(userSelectedTimezone)
And saving the date in the database, I used this in C#:
var utcFromClient = Record.DownTimeStartUTC.ToUniversalTime()

How to get local hour from moment.js

I'm using moment.js to display differents date and times using
moment().format('llll');
It provide result like that in english
Tue, Oct 21, 2014 1:11 PM
and like that in french
mar. 21 oct. 2014 13:11
But I want to display only time (1:11PM or 13:11) and not the full date.
How can I do that ?
EDIT: The perfect thing would be to display seconds
1:11:15 pm and 13:11:15
To get only the localized time, in moment.js you have the 'LT' formatter:
moment().format('LT');
the result is the localized time :
1:11PM
Unfortunately, it seems that there are no formatters for localized time displaying seconds.

moment.js converting epoch date to specific timezone

I've been looking for days to find how to get moment.js to behave correctly and return the correct date for a specific local time zone.
Here is my challenge:
I'm calling a flight api to get the "arrival date/time" of a flight. It provides me the arrival time in epoch time and a timezone for the airport.
I'm using javascript moment.js to convert that to the local time of the airport, BUT, the time always comes in a couple days ahead.
Here's my code:
var dateVal = 1395184260;
var day = moment.unix(dateVal).tz('America/Vancouver').format();
console.log("tz :",day);
// should return: 4:21 PM - Sun Mar-16-2014 BUT it always returns the 18th instead of the 16th.
Where are you getting the "should return" from?
According to http://www.epochconverter.com/epoch/timezones.php?epoch=1395184260, your time should be
Mar 18 2014 16:11:00 GMT-7:00
This fiddle using your timestamp:
var dateVal = 1395184260;
var date = moment.unix(dateVal);
console.log(date.tz("America/Vancouver").format('ll HH:mm:ss Z'))
returns:
Mar 18 2014 16:11:00 -07:00
I'd check whatever converter you're using to see if there's a bug.

Categories