AWS Lambda different date result using moment JS - javascript

My time zone is GMT+8. and my AWS region is Singapore (ap-southeast-1)
My concern is they have different results when calculating dates, when i deployed my code in aws/lambda, i got different result from my local machine. what I want to achieve or my goal is that the AWS Lambda will have a same result like in my local
my local result: 2023-04-05T16:00:00.000Z
lambda result: 2023-04-06T00:00:00.000Z
code:
const moment = require('moment');
const dateToday = new Date();
const today = dateToday.toLocaleDateString();
const accumulatedDate = moment.utc(new Date(today)).add(118, 'days').toISOString();
console.log(accumulatedDate);

The toLocaleDateString() method returns a string with a language-sensitive representation of the date portion of the specified date in the user agent's timezone.
I think the issue is that you are converting your local timestamp to be represented as UTC, rather than just using UTC.
The toUTCString() method converts a date to a string, interpreting it in the UTC time zone.

You're seeing this result because toLocaleDateString() truncates the time. But "truncate the time" is inherently a timezone-sensitive operation. If you convert a date+time to a date, you need to decide which time zone's midnight you're going to use to truncate the time.
For example, assume a time like 2000-01-01T04:00Z. In New York (UTC-5), toLocaleDateString('en-US') would return '12/31/1999' (which, when converted to UTC, is 1999-12-31T05:00Z). While in London it'd return '2000-01-01' (which, when converted to UTC, is 2000-01-01T00:00Z).
If you want to get the same result on your local machine as on the server, then you'll need to use the same time zone in both places. Which time zone you use depends on the use cases of your app. For example, if you want to report on "Sales made yesterday at our store in Shanghai" then you'll probably want to use the Asia/Shanghai time zone. If you are writing to a log file, then you'll probably want to use UTC. If you're summarizing revenue for a multinational corporation headquartered in Marseille, then you'll probably want to use Europe/Paris. And so on.
BTW, instead of moment.js. you may want to look at Temporal, which is a new JavaScript built-in object that will be shipping in browsers and Node.js soon, likely within the next year or so. Temporal is the successor API to JavaScript's venerable Date object, and it has first-class support for time zones and date/time arithmetic. There are Temporal polyfills available now. (Full disclosure: for the last few years I helped to lead the team that designed the Temporal API.)
Using Temporal, your code could look something like this:
import { Temporal } from '#js-temporal/polyfill';
// If you want to use UTC
const today = Temporal.Now.plainDateISO('UTC'); // 2022-12-14
const accumulatedDate = today.add({ days: 118 }).toString(); // 2023-04-11
// If you want to use a specific time zone
const today = Temporal.Now.plainDateISO('Asia/Singapore'); // 2022-12-15
const accumulatedDate = today.add({ days: 118 }).toString(); // 2023-04-12

Related

How can use "Romance Standard Time" to set the time zone?

I have the UTC date string "2022-01-06T13:35:00Z" and the time zone string "Romance Standard Time". How can use that time zone string in JavaScript (in a browser) so that I can get the time corrected to 14:35?
The time zone libraries that I have found so far uses the IANA time zone, e.g. "Europe/Copenhagen", so a library that can convert "Romance Standard Time" to something like "Europe/Paris" would also answer my question. It's acceptable that this conversion is done in .NET and not JavaScript.
The key was to understand that "Romance Standard Time" is a Windows time zone ID. Everyone else uses IANA time zone IDs. They have the region/city format, e.g. "Europe/Copenhagen".
In .NET 6 it's possible to convert between the formats. Here's the code example from Date, Time, and Time Zone Enhancements in .NET 6.
// Conversion from Windows to IANA when a region is unknown.
string windowsTimeZoneId = "Eastern Standard Time";
if (!TimeZoneInfo.TryConvertWindowsIdToIanaId(
windowsTimeZoneId, out string ianaTimeZoneId))
{
throw new TimeZoneNotFoundException(
$"No IANA time zone found for "{windowsTimeZoneId}".");
}
Console.WriteLine($"{windowsTimeZoneId} => {ianaTimeZoneId}");
// "Eastern Standard Time => America/New_York"
// Conversion from Windows to IANA when a region is known.
string windowsTimeZoneId = "Eastern Standard Time";
string region = "CA"; // Canada
if (!TimeZoneInfo.TryConvertWindowsIdToIanaId(
windowsTimeZoneId, region, out string ianaTimeZoneId))
{
throw new TimeZoneNotFoundException(
$"No IANA time zone found for "{windowsTimeZoneId}" in "{region}".");
}
Console.WriteLine($"{windowsTimeZoneId} + {region} => {ianaTimeZoneId}");
// "Eastern Standard Time + CA => America/Toronto"
If you're on an earlier version of .NET you can use TimeZoneConverter. Here's a complete list of the time zones in case you need to build your own converter: windowsZones.json.
This answer to this questions suggests using NodaTime, so that is probably also a possibility: Convert Windows timezone to moment.js timezone?
JavaScript
If you want to do it with Javascript, there is multiple Libraries. I am most familiar with moment.js, however they are deprecated, which means you might want to use another library if you are working on a new project.
List of suggested libraries by moment.js.
Anyways, if you wish to work with moment and convert to timezones, you could easily do that using Moment-Timezone. All supported timezones.
For example:
const moment = require('moment-timezone');
const timeZone = "Europe/Paris";
const ISOString = "2022-01-06T13:35:00Z"; //2022-01-06T13:35:00Z
const momentDefault = moment(ISOString).format(); //2022-01-06T14:35:00+01:00
const momentTz = moment.utc(ISOString).tz(timeZone).format(); //2022-01-06T14:35:00+01:00
As you see, moment gets the timezone by default and handels the ISOString as a UTC value, so it automatically converts the value to the timezone of the client user.
You still can specifically tell moment to handle the ISOString as a UTC ISOString and then convert it to a specific Timezone you defined. In that way the client's timezone will be ignored.
EDIT:
Now I realized that the questioner wants to convert the timezone from Windows to Iana before converting it in Javascript, because most libraries including Moment.js don't support windows timezone ids.
I found a nice library here.
And here is an example how to convert the timezone first and then use moment.js.
import { findIana } from 'windows-iana';
const moment = require('moment-timezone');
const result = findIana('Romance Standard Time');
console.log(result); // ['Europe/Paris', 'Europe/Brussels', 'Europe/Copenhagen', 'Europe/Madrid', 'Africa/Ceuta']
const timeZone = result[0]; //doesn't really matter which one to take, if you are just converting the times.
const ISOString = "2022-01-06T13:35:00Z"; //2022-01-06T13:35:00Z
const momentDefault = moment(ISOString).format(); //2022-01-06T14:35:00+01:00
const momentTz = moment.utc(ISOString).tz(timeZone).format(); //2022-01-06T14:35:00+01:00
.NET C#
To convert a time to a specific timezone in C#, you dont need any extra packages, you can simply do that as following:
var isoString = "2022-01-06T13:35:00Z";
var utcDate= DateTime.Parse(isoString);
var timeZone = "Romance Standard Time";
var date = TimeZoneInfo.ConvertTime(utcDate, TimeZoneInfo.FindSystemTimeZoneById(timeZone)); //01/06/2022 14:35:00
Here you can find list of all supported timezoneIds

How to make Moment.js ignore the user's timezone?

I've got a form where I input an event that starts at a certain time. Let's say 9am.
To assign a date/time object I'm using MomentJs. The issue comes when displaying it in different time-zones.
In London will show up 9am as intended - in Kiev will show 11am.
How can I make MomentJS and the browser ignore which timezone is relevant for the user, and just displaying the time I'm giving?
Here's my code:
<p>
Start time:
{moment(event.startDate).format("HH:mm")}
</p>
Assuming you have stored the date as utc (which in this case you probably should have), you could use the following:
moment.utc(event.startDate).format("HH:mm")
Let me provide an alternative answer in Vanilla JavaScript. If you want to make it timezone 'neutral', you can first convert it to UTC using toISOString().
const current = new Date();
const utcCurrent = current.toISOString();
console.log(utcCurrent);
If you want to convert it to a specific timezone, such as London, you can use toLocaleString(). Do take note of the browser support for the timezone though.
const londonTime = new Date().toLocaleString('en-US', { timeZone: 'Europe/London' })
console.log(londonTime);
What you want is a normalized Datetime. This can get a little confusing since the concept of timezones is a rather arbitrary construct.
I like to think of Datetime values as "absolute" and "relative". An "absolute" Datetime is one that is true regardless of which timezone you're in. The most common example of these are UTC(+000) and UNIX Time (also known as Unix epoch, POSIX Time or Unix Timestampe).
UTC is pretty obvious. Its the current time at +000 timezone. UNIX time is a bit more interesting. It represents the number of seconds that have elapsed since January 1, 1970.
You should always store data, in both client and backend, as an "absolute" time. My preference is UNIX time since its represented as a single integer (nice and clean).
moment.js does this for you. When you instantiate your moment object, you can use:
var date = moment.utc(utcString)
or for Unix Time
var date = moment.unix(unixInt)
You can then use this object to display the date in any form you wish:
console.log(date.tz.("America/Toronto"))
The only way I could solve this is by removing the timezone and milliseconds info from the string. I used date-fns lib but I imagine moment will work the same way.
import { format } from 'date-fns'
const myDateTimeString = '2022-02-22T19:55:00.000+01:00'
const dateTimeWithoutTimezone = myDateTimeString.slice(0, 16) // <- 2022-02-22T19:55
format(new Date(dateTimeWithoutTimezone), 'HH:mm')

How to guess user's timezone using date-fns?

I have a requirement, where I need to show a user's time in their local time zone. This needs to be done using date-fns.
The following code checks the current time and then given a timezone converts it into local time as per the time zone.
const { formatToTimeZone } = require('date-fns-timezone')
let date = new Date()
const format = 'D.M.YYYY HH:mm:ss [GMT]Z (z)'
const output = formatToTimeZone(date, format, { timeZone: 'Asia/Calcutta' })
However, how do I guess the user's timezone on the fly?
In moment.js, you can get it with moment.tz.guess(). But how can I do it without moment.js and by using date-fns?
https://runkit.com/embed/835tsn9a87so
UPDATE: I will be using this inside a VueJS application. So, if there are any other related solutions, those are welcomed as well. Thanks.
To get the user's IANA time zone identifier, most modern browsers now support the following:
Intl.DateTimeFormat().resolvedOptions().timeZone
That said, the usual reason you would need to use formatToTimeZone from date-fns-timezone is when you need to use a different time zone other than the user's local zone. Otherwise, you can usually just use the format function from date-fns.
However, in your case, you are also trying to use the z format specifier to display the user's time zone abbreviation. This isn't provided by date-fns directly, so if that is critical then you will indeed need to get the user's time zone with the Intl api shown above and use formatToTimeZone.
Do keep in mind though that these abbreviations are whatever the IANA data has recorded, which are in English only, and it doesn't have abbreviations for every time zone. For those that don't, you will see a numeric value instead, such as -02.
Also, many abbreviations can be ambiguous (such as the I in IST possibly meaning India, Israel, or Ireland, and many others...). Thus, in most cases, if you don't need the abbreviation, you're often better off without it.
Just solved a similar problem myself. The trick is to use the format function from date-fns-tz instead of the one from date-fns.
import { format } from "date-fns";
console.log(format(new Date(), "yyyy-MM-dd HH:mm z"));
// 2021-11-29 13:55 GMT-8
import { format } from "date-fns-tz";
console.log(format(new Date(), "yyyy-MM-dd HH:mm z"));
// 2021-11-29 13:55 PST
See documentation here:
https://date-fns.org/v2.27.0/docs/Time-Zones

Unit testing handling of date inputs in JavaScript regardless of time zone

I have a form where a user can enter a date, i.e. <input type="date"> the value is submitted in yyyy-MM-dd format. When I create a Date object with the string it assumes the time zone is the one the user's browser is set to – this is the behavior I want.
I'm then using the date value to make queries against a REST API that expects ISO date/time strings. That's no problem as the toISOString function on the Date object handles everything correctly.
However, when I'm unit testing this code – setting my input to a yyyy-MM-dd string then asserting that the output is an expected ISO timestamp string the tests can only work in a particular time zone. Is there a way I can force the time zone in the test?
I've tried using Jasmine spies to do something like:
var fixedTime = moment().zone(60).toDate()
spyOn(window, 'Date').andCallFake(function() {
return fixedTime;
});
But given there are so many variants of the constructor and so many ways it gets called by moment.js this is pretty impractical and is getting me into infinite loops.
A JavaScript Date cannot be set to a particular time zone. It only knows about UTC and the computer's local time from the environment it is running on.
There are time zone libraries for javascript, but I don't think that will help you here.
First, understand that "ISO" refers to ISO8601, which is a specification that defines a collection of related formats, such as YYYY-MM-DDTHH:MM:SS.
It is a separate concept from UTC, which refers to Universal Coordinated Time. UTC is the timekeeping system that we all synchronize our clocks to, which uses GMT as its basis - that is, the time in effect at the prime meridian not adjusted for daylight saving time.
Put together, the Date.toISOString() method will return the UTC form of an ISO8601 formatted timestamp, such as 2013-09-20T01:23:45Z. The Z at the end indicates that the time is in UTC.
But a value such as 2013-09-20 is still ISO formatted - it's just that it only has precision to the whole day, which means that it can't carry any time zone information.
When you use <input type="date">, the resulting value is not a Date class. It's a string containing the ISO formatted YYYY-MM-DD. You should just pass this directly to your application.
Now if what you are looking for is the full date and time, at midnight in the local time zone, of the date selected, and adjusted to UTC, well that's a different story. It is certainly doable but you have to understand that it is not the same as just passing the calendar date.
The easiest way to do that would be with moment.js as follows:
var s = "2013-09-20"; // from your input's value property
var m = moment(s);
var result = m.toISOString(); // "2013-09-20T07:00:00.000Z"
The value is adjusted because my time zone offset is -07:00.
You can do it without moment, but you have to replace dashes with slashes or the original value will be interpreted as if it is already in UTC.
new Date(s.replace('-','/')).toISOString()

json dates and timezones

I have the following code:
$(function () {
var thedate = "/Date(1198908717056)/";
var thedate2 = ProcessDate(thedate)
alert(thedate2);
});
function ProcessDate(DateString) {
var TheDate = eval(DateString.replace(/\/Date\((\d+)\)\//gi, "new Date($1)"));
return TheDate;
}
When it runs, it returns an alert with December 29 and the time is showing as Eastern Time. When I change the timezone on my computer, it's still showing the date in the Eastern timezone.
My question is this: does the string "/Date(1198908717056)/" contain the timezone information or is the timezone displayed in the alert the result of the browser determining my timezone?
Thanks.
JSON doesn't have dates at all (it's one of JSON's flaws). Those strings are just strings.
Some frameworks, like ASP.Net, use that syntax to indicate dates. What timezone they're in will be dictated by the framework. I believe the dates are in UTC and so you can just use the new Date(Number) constructor to create them (more in this other answer). That creates the date by directly setting its internal "milliseconds since The Epoch UTC" value, more in section 15.9 of the specification. Mind you, that only works if, in fact, whatever it is creating these pseudo-date strings is using UTC.
Update: Looking at your code, although it works, this line:
var TheDate = eval(DateString.replace(/\/Date\((\d+)\)\//gi, "new Date($1)"));
...is an abuse of eval. eval should be avoided whenever possible. Instead, if you want to keep it as a one-liner:
var TheDate = new Date(Number(DateString.replace(/\/Date\((\d+)\)\//gi, "$1")));
...or somewhat more readably:
var Match = /\/Date\((\d+)\)\//gi.exec(DateString);
var TheDate;
if (Match) {
TheDate = new Date(Number(Match[1]));
}
In all of those cases, the Date will be initialized with the UTC time value embedded in the date string. But then when you ask JavaScript to format the date (for instance, via toString), it will use your local timezone to do that. You haven't shown how you're outputting the date, so I can't tell you why the timezone seems not to change if you change your timezone (perhaps the browser didn't pick up the change?). When I do it, if I output the date as a string, it shows it in British Summer Time (which is my current timezone) if I use toString, or UTC if I use toUTCString. Here's a live example using both your original date, and a date (today's date, as I write this) that's in daylight savings time so even in the UK you can see the difference between UTC and local time.
Off-topic: In JavaScript, the overwhelming convention is to use camelCased names starting with a lower-case letter for both local variables and function names. So, theDate rather than TheDate. Initial caps are reserved for constructor functions (like Date). You're free to ignore the convention, of course, but it will tend to make it difficult for others to read your code.
The timezone is taken from your current system setting. Have a look at the Date class.
The given value is in milliseconds and does not contain a timezone. The constructor of Date() expects the milliseconds to be given in UTC. If you have values with a known timezone, you should use the dateString constructor version.
However, as far as I know, there is no way convert between timezones in JavaScript, except for UTC and the local system timezone.

Categories

Resources