I am in Hawaii. From Angular, I want to send Pacific Standard Time (PST) to C# Net Core API. It will save it in database and save in Pacific Standard Time. (I didn’t create the architecture, just noting).
The whole Angular Application date/times are written in reference of PST.
Example goal is to Schedule Date at 4:30PM PST
We learned a bug today, if we send a date "2021-03-17T16:30:00"
, our application creates new Date("2021-03-17T16:30:00")
in Hawaii Timezone misinterprets. Then C# probably does the right thing, and converts any time to Pacific Local time (TimeZoneInfo.ConvertTime(dateTime, TimeZoneInfo.FindSystemTimeZoneById("America/Los_Angeles"))
. Thus we incorrectly convert to 7:30PM.
Our API Request Data type is in Date. Would this solution work? however, I feel last 4th line will not account for Daylight savings, or can create issue.
const inputDate = "2021-03-17T16:30:00"; const pstMoment = moment.tz(inputDate, 'America/Los_Angeles'); const clientTimeZoneName = Intl.DateTimeFormat().resolvedOptions().timeZone; const clientMoment = pstMoment.clone().tz(clientTimeZoneName); console.log(new Date(clientMoment.format())); // this will send to API
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.33/moment-timezone-with-data-10-year-range.js"></script>
Note: Code resolution should not only work in Hawaii, but other global countries which may Not have Daylight Savings Time. Our schedule datepicker utilizes a string storage type (inputDate).
Typescript class
export interface ScheduleDto { scheduleDate?: Date; scheduleDate: "2021-03-18T02:30:00.000Z"
C# class
public class ScheduleDto { public DateTime? ScheduleDate { get; set; } .... return TimeZoneInfo.ConvertTime(ScheduleDate , TimeZoneInfo.FindSystemTimeZoneById("America/Los_Angeles"));
Advertisement
Answer
If I understand correctly, the problem is that your current approach on the client-side is just creating a Date
object like new Date("2021-03-17T16:30:00")
, which is going to use the local time zone to determine the point-in time you’re talking about. You want it to always be interpreted as Pacific time, but you don’t know which offset to use because of DST.
So then, the ultimate answer to your question is – YES, the code you wrote using Moment-timezone, would indeed apply the correct offset. However, it’s a bit verbose. You don’t actually need to do anything with regard to detecting the current local time zone. You can instead just build the Date
object with:
moment.tz('2021-03-17T16:30:00', 'America/Los_Angeles').toDate()
Given Moment’s project status, it would be preferred to use Luxon instead (unless you have already extensively used Moment in your project). In Luxon, that would be:
luxon.DateTime.fromISO('2021-03-17T16:30:00', {zone: 'America/Los_Angeles'}).toJSDate()
Or you could use the zonedTimeToUtc
function from date-fns-tz.
The point is, since you’re constructing a Date
object, you’re always sending some string representation of it over the wire. You appear to be serializing those Date
objects with .toISOString()
, which will send the UTC equivalent "2021-03-18T02:30:00.000Z"
. Getting that UTC point in time correct is what matters most.
In your .NET code, if you are receiving that value into a DateTime
object, then its Kind
property will be set to Utc
because of the Z
at the end of the string. TimeZoneInfo.ConvertTime
will use the Kind
property to determine the source time zone for the conversion, and you’ve supplied the destination time zone as Pacific time.
A much simpler approach would be to not use a Date
object in your client-side code, but rather you would send the intended date and time over the wire instead, without the offset "2021-03-17T16:30:00"
. In your .NET code, the DateTime.Kind
would be Unspecified
. Then you wouldn’t call TimeZoneInfo.ConvertTime
at all, because you already have the value in the desired time zone.
Alternatives:
For the TypeScript data type, You could use a string.
In the future, when Temporal is finished and fully integrated into ECMAScript, you could use a PlainDateTime
.