Convert DateTime with DateTimeKind.Unspecified from utc to local - nodatime

I have a database where all dates are UTC, and the driver always sends me DateTime objects with DateTimeKind.Unspecified. I want to assume they are in UTC and convert to local time.
What is the simplest way to achieve this using NodaTime?
Instant.FromDateTimeUtc(utcDate).InZone(localZone); keeps complaining DateTimeKind should be Utc.

If you're definitely using Noda Time and want a ZonedDateTime, you could "tell" Noda Time that you've really got a UTC value, then convert it:
var zoned = LocalDateTime.FromDateTime(utcDate)
.InZoneStrictly(DateTimeZone.Utc)
.WithZone(localZone);
Or you could just use DateTime.SpecifyKind to start with:
var utcDateTime = DateTime.SpecifyKind(unspecifiedDateTime, DateTimeKind.Utc);
... and then use your existing code, or take Noda Time out of the picture entirely if you want.
Indeed, just DateTime.ToLocalTime() would be fine if you don't need Noda Time elsewhere:
var localDateTime = utcDateTime.ToLocalTime();
... the BCL will assume that an unspecified date/time is UTC if you call ToLocalTime() on it. Of course, I'd recommend using Noda Time everywhere though :)

Instant now = SystemClock.Instance.GetCurrentInstant();
DateTimeZone TimeZone = DateTimeZoneProviders.Tzdb.GetSystemDefault();
var zoned = LocalDateTime.FromDateTime(msg.MessageSentUtc)
.InZoneStrictly(DateTimeZone.Utc)
.WithZone(TimeZone);
Simplified...

Related

What is equivalent of TimeZoneInfo.ConvertTime in NodaTime?

I want to use the NodaTime library to convert the date from one timezone to another like this.
string fromSystemTimeZoneId = "GMT Standard Time";
string toSystemTimeZoneId = "Central Standard Time";
TimeZoneInfo fromTimeZone = TimeZoneInfo.FindSystemTimeZoneById(fromSystemTimeZoneId);
TimeZoneInfo toTimeZone = TimeZoneInfo.FindSystemTimeZoneById(toSystemTimeZoneId);
var convertedTime = TimeZoneInfo.ConvertTime(inputDateTime, fromTimeZone, toTimeZone);
The above code works perfectly fine for me, But now I want to use IANA standard time zone (like Europe/London and America/Chicago) in place of windows OS-provided time zone ids.
I am using .net 4.7.2 and cannot upgrade the framework due to some limitations.
I have gone through this answer, But I am looking for simple few lines of code nothing complicated.
But I am looking for simple few lines of code nothing complicated.
But you're trying to do something complicated. Noda Time makes everything explicit, which means it's clear exactly what's going on - at the cost of being a little more verbose.
DateTime has no concept of a time zone itself (other than for the special cases where the Kind is Utc or Local). So TimeZoneInfo.ConvertTime has to:
Consider what instant in time is represented by inputDateTime in fromTimeZone
Work out what that instant in time looks like in outputDateTime
In Noda Time, those are are two separate operations, if you want to start and end with a LocalDateTime:
LocalDateTime inputDateTime = ...;
DateTimeZone fromTimeZone = ...;
DateTimeZone toTimeZone = ...;
// There are options for how this conversion is performed, as noted in other questions
ZonedDateTime inputDateTimeInFromTimeZone = inputDateTime.InZoneLeniently(fromTimeZone);
// This conversion is always unambiguous, because ZonedDateTime unambiguously
// refers to a single instant in time
ZonedDateTime inputDateTimeInToTimeZone = inputDateTimeInFromTimeZone.WithZone(toTimeZone);
LocalDateTime localPart = inputDateTimeInToTimeZone.LocalDateTime;
So that's basically the equivalent conversion - but you need to be explicit about how you want to handle skipped/ambiguous inputs. If you want everything in your app to use the same conversion, you can wrap that in a method that looks just like TimeZoneInfo.ConvertTime. But why not just keep things in a ZonedDateTime instead of LocalDateTime to start with? Then you don't get into the ambiguous position - other than potentially when converting user input (which is entirely separate from converting from one time zone to another).

How to convert the local browser time to utc time unsing moment.js

Tried multiple methods to convert the local time to UTC. Tried Offset(420) as the time difference is UTC 7 and it worked. So here what i need is my users will be giving a request from different timezones and all of them should convert to UTC. So when giving time from different timezone the UTC time difference will also change how it can be identified and change accordingly. how can i do that?
You can use moment.utc() to get UTC time. If you wish to send it to the server, it's probably best to send as an ISO-8601 date string.
const localDate = moment();
const utcDate = moment.utc();
console.log("Local time:", localDate.format("YYYY-MM-DD HH:mm:ss"));
console.log("UTC time:", utcDate.format("YYYY-MM-DD HH:mm:ss"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js"></script>

Mongoose datetime and timezone, how to get datetime based on server timezone

The first answer of this question suggests that mongoose would adapt the date according to server timezone when retrieving data.
However, I don't have this comportement.
I set the (node) server timezone with :
process.env.TZ='Europe/Paris'
For exemple if I create a simple model like :
const mongoose = require("mongoose");
const testSchema = new mongoose.Schema({
myDate: { type: Date, required: true },
}, { timestamps: true });
exports.Comment = mongoose.default.model('TestSchema', testSchema);
But if I create a date with 2020-01-01 20:20:20, when doing TestSchema.find() the date will be: 2020-01-01T19:20:20.000Z so there are two things that I don't understand :
Europe/Paris is actually UTC +2, so I would expect the date to be either 2020-01-01T18:20:20.000Z in UTC or 2020-01-01T20:20:20.000Z with the server timezone
How to have mongoose automatically set the date to the correct timezone?
I know that myDate is a Date object, so I can convert it manually but I'd rather not have to do it myself for simple reasons like forgetting to convert one of the dates in the application or not having to do it every time a Date field is added
An easy solution that I can think of would be to register a global plugin for mongoose which would use schema.set('toJSON', ... and schema.set('toObject', ...) with the transform method so I can loop through schema fields and if the field is a Date, update it to my timezone.
But I see two problems with this approch :
It doesn't sound very good performance-wise if I am querying a lot of documents each with a lot of fields
As you can see here I am currently not able to register global plugins...
What would be the best method to get the date in the server timezone format? I would rather still store them in UTC but set the hour according to the server timezone.
EDIT :
I just saw that while console.log(myDate) outputs 2018-01-01T19:20:20.000Z console.log(myDate.toString() outputs Mon Jan 01 2018 20:20:20 GMT+0100 (Central European Standard Time) so it seems likes this could be used, even tho I'd rather still have a Date object and converting it to string just before sending it to the client (would need some formatting tho since this format is not very user friendly). But then again, how would I do this globally and not for every date
A few things:
Europe/Paris at 2020-01-01T20:20:20 is UTC+1. It doesn't switch to UTC+2 until Summer Time kicks in on March 29th. Reference here. Thus the conversion to 2020-01-01T19:20:20Z is correct.
The output of console.log when passed a Date object is implementation specific. Some implementations will emit the output of .toString() (which is in local time in RFC 2822 format), and some will emit the output of .toISOString() (which is in UTC in ISO 8601 extended format). That is why you see the difference.
In general, it is not good to send a local time without also sending a time zone offset. ISO 8601 format is ideal, but you should send either 2020-01-01T19:20:20Z, or 2020-01-01T20:20:20+01:00. Don't just send the date and time without an offset to the client. Otherwise, if your client could be in a different time zone then they would interpret the value incorrectly.
Keep in mind that Date objects are not time zone aware. They contain only a Unix timestamp internally, and they convert only to the system's local time zone for the functions that work in local time. They cannot work in any other time zone.
Relying on the system local time zone is bad for portability. One doesn't always have the ability to change it, and it doesn't do well when you have to work in multiple time zones. It would be better to not rely on setting a local time zone from Node's TZ variable. Instead, consider writing your code to be independent of any local time zone setting.
A time zone aware date library can help with most of your concerns. I can recommend Luxon, js-Joda, Moment + Moment-Timezone, or date-fns + date-fns-timezone.
"how would I do this globally" is something I'm not following in your question. Try the approach I described, and if you still have issues then open a new question. Try to be specific and ask a single question. You're likely to get better results that way. Please read How do I ask a good question? and How to create a Minimal, Complete, and Verifiable example. Thanks.
To solve the issue:
npm i mongoose-timezone
In your schema file:
import timeZone from "mongoose-timezone";
const testSchema = new mongoose.Schema({
myDate: { type: Date, required: true },
}, { timestamps: true });
// mongoose will save the dates based on user's timezone
testSchema.plugin(timeZone)
mongoose-timezone basically adds the current timezone offset to the
date before store and removes the offset when retrieving data. This
way dates are kept proportional in the database and in the app.

Are Alexa skill dates the same in the Service Simulator and the Echo?

My Alexa node.js skill involves getting the current date using "new Date()". In the Service Simulator the date returned is UTC. But I need the time in "America/New_York" -- my skill is local to New York. So I can convert the time zone, no problem. But I'm wondering whether this will get the same result when I deploy the skill. That is, does the Date() function on the actual Service convert to local time from UTC? If it does, then I will need some way of determining in my code whether I am in the Service Simulator or the actual Service, and converting to New York time in my accordingly.
Thank you.
From the documentation for Date
If no arguments are provided, the constructor creates a JavaScript Date object for the current date and time according to system settings.
So depending on the system settings the timezones can be different.
To overcome this you can use UTC date everywhere and then simply convert the timezone where needed.
// date with some timezone depending on system
let date = new Date();
// date in UTC
let utcDate = new Date(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds());
Note: utcDate will still be in the system timezone, but the actual value it holds will represent the correct date and time in UTC.

How to get the local timezone from the system using nodejs

Is there a way to obtain the local timezone from the system (eg:- ubuntu) using nodejs?
I used moment.js to extract the date and time values. But couldn't find a way to extract the timezone as well.
The existing answers will tell you the current timezone offset, but you will have issues if you are comparing historic/future points in time as this will not cater for daylight saving changes.
In many timezones, the offset varies throughout the year and these changes occur at different dates or not at all depending on the latitude. If you only have UTC time and an offset, you can never be sure what the offset will be in that location at various other times during the year.
For example, a UTC+2:00 offset could refer to Barcelona in the summer or Ivory Coast all year round. The 2hr offset will always display the correct time in Ivory Coast but will be 1hr out for half the year in Barcelona.
Check out this great article covering the above.
How do we cater for all these time zone issues? Well, it's pretty simple:
Save all times in UTC
Store the time zone string for where this event occurred
In modern browsers or node.js, you can get the local IANA time zone string like this:
Intl.DateTimeFormat().resolvedOptions().timeZone // eg. 'America/Chicago'
You can then use this timezone string in a library like Luxon to help offset your captured UTC times.
DateTime.fromISO("2017-05-15T09:10:23", { zone: "Europe/Paris" });
It is very simple.
var x = new Date();
var offset= -x.getTimezoneOffset();
console.log((offset>=0?"+":"")+parseInt(offset/60)+":"+String(offset%60).padStart(2, "0"))
And there is nothing else or you can see if momentJS can help you or not.
Note: This answer is outdated, you can suggest to add in it.
It is this easy, no libraries needed:
console.log("test ...")
let d = new Date()
console.log("UTC time " + d)
let ank = d.toLocaleString('en-US', { timeZone: 'America/Anchorage' });
console.log("your time zone " + ank)
How to see the exact time zone names on most servers:
ls /usr/share/zoneinfo
Works flawlessly:
You'll get the correct time-text regardless of daylight savings issues, etc etc.
Handy related mysql tip:
On almost all servers, mysql also needs to know the tz info.
Basically the solution is, on the shell
sudo mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql mysql
.. google more about it.
I solved this using moment.js (http://momentjs.com/docs/)
var moment = require('moment');
var offset = moment().utcOffset();
console.log(''.concat(offset < 0 ? "-" : "+",moment(''.concat(Math.abs(offset/60),Math.abs(offset%60) < 10 ? "0" : "",Math.abs(offset%60)),"hmm").format("HH:mm")));
------Edited--------
I found a better solution using moment.js. Just use moment().format('Z')
which gives the output :
+05:30

Resources