I'm trying to remove the javascript Date offset, so that the local time a date was recorded in from a given country can be displayed.
I have a test that only works when the timezone is GMT
describe('.removeLocalDateOffset()', () => {
it('removes the timezone offset', () => {
const input = '2017-10-03T08:53:12.000-07:00';
const result = removeLocalDateOffset(input);
expect(result.toISOString()).toBe('2017-10-03T08:53:12.000Z');
});
});
And the function I want to do the job:
const removeLocalDateOffset = (date) => {
const originalDate = new Date(date);
return new Date(Date.UTC(
originalDate.getFullYear(),
originalDate.getMonth(),
originalDate.getDate(),
originalDate.getHours(),
originalDate.getMinutes(),
originalDate.getSeconds(),
));
}
Any suggestions for how I can do this using the methods of the new Date() object? Ideally not doing a .slice() on a substring.
Test Results. I am currently in GMT:
Expected: "2017-10-03T08:53:12.000Z"
Received: "2017-10-03T16:53:12.000Z"
Related
I am working on displaying a banner on a website, between two dates (the campaign's start date and end date).
For this purpose, I have the following function:
function checkCampaignActive() {
const campaignDateStart = new Date('2022-09-14');
const campaignDateStop = new Date('2022-09-15');
const today = Date.now();
const isCampaignStarted = today >= campaignDateStart.getTime();
const isCampaignExpired = today > campaignDateStop.getTime();
this.isCampaignActive = isCampaignStarted && !isCampaignExpired;
console.log('Is started: ', isCampaignStarted);
console.log('Is expired: ', isCampaignExpired);
console.log(isCampaignActive);
}
checkCampaignActive();
The problem
Since getTime() returns the milliseconds between Jan 1 1970, 00:00 GMT and 2022-09-14 and 00:00 GMT and my local time is not GMT, there is a gap between the desired campaign start and the real one.
Whatever new Date('2022-09-14') returns has to be adjusted for the local time, but remain an object, not a string.
What is the easiest way to fix this issue?
The cause of the "problem" is that the date string your code provides to the Date constructor is interpreted as a simplified ISO 8601 format, denoting UTC.
The best way is to avoid a string typed argument, and provide numeric arguments. The equivalent of your example would be:
const campaignDateStart = new Date(2022, 8, 14);
const campaignDateStop = new Date(2022, 8, 15);
(Be aware of the zero-based month numbering)
It is possible to get away with it using strings. For instance, these options work because they step away from the format that JavaScript will interpret as UTC:
Append a time specification (without appending "Z" or other time zone specifier);
const campaignDateStart = new Date('2022-09-14 00:00');
const campaignDateStop = new Date('2022-09-15 00:00');
As stated by Mozilla Contributors:
Date-only strings (e.g. "1970-01-01") are treated as UTC, while date-time strings (e.g. "1970-01-01T12:00") are treated as local.
Or use a different delimiter:
const campaignDateStart = new Date('2022/09/14');
const campaignDateStop = new Date('2022/09/15');
But these rely on the complex rules of how strings are parsed as dates. Some of that logic is host-dependent, so in general it is better to avoid passing strings to the date constructor (or to Date.parse which uses the same logic for string arguments).
A small change to your code will make it work the way you wish.
When you call new Date('2022-09-14') it returns the number of milliseconds from 1970-01-01 00:00:00 UTC to 2022-09-14 00:00:00 UTC, however you actually with to get the number of milliseconds from 1970-01-01 00:00:00 UTC
2022-09-14 00:00:00 [local timezone].
It's easy to make this change, simply parse '2022-09-14 00:00:00' instead, and the same with the subsequent date. This will return the expected values and give the correct answer.
function checkCampaignActive() {
const campaignDateStart = new Date('2022-09-14 00:00');
const campaignDateStop = new Date('2022-09-15 00:00');
const today = Date.now();
const isCampaignStarted = today >= campaignDateStart.getTime();
const isCampaignExpired = today > campaignDateStop.getTime();
this.isCampaignActive = isCampaignStarted && !isCampaignExpired;
console.log('Is started: ', isCampaignStarted);
console.log('Is expired: ', isCampaignExpired);
console.log(isCampaignActive);
}
checkCampaignActive();
.as-console-wrapper { max-height: 100% !important; }
Visit this link: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getTimezoneOffset
Add GMT in Date to add your timezone. Then use .getTimezoneOffset to get gap in Minutes.
function checkCampaignActive() {
const campaignDateStart = new Date('2022-09-14 GMT+5:45');
const campaignDateStop = new Date('2022-09-15 GMT+5:45');
const today = Date.now();
const today1 = Date.now() + campaignDateStart.getTimezoneOffset() * 60;
const isCampaignStarted = today >= campaignDateStart.getTime();
const isCampaignExpired = today > campaignDateStop.getTime();
this.isCampaignActive = isCampaignStarted && !isCampaignExpired;
console.log('Is started: ', isCampaignStarted);
console.log('Is expired: ', isCampaignExpired);
console.log(isCampaignActive);
console.log(today);
console.log(today1);
console.log(campaignDateStart.getTimezoneOffset());
}
checkCampaignActive();
I tried using the intervalToDuration function from date-fns but I keep getting an error that says End Date is invalid.
My code is as follows
import { intervalToDuration} from "date-fns";
remaining() {
const now = new Date();
const end = this.endDate;
return intervalToDuration({
start: now,
end: end,
});
},
this.endDate is dynamically populated but for this question is equal to 2021-02-26T00:00:00.000Z
Since your endDate variable is coming from an API, it is being stored as a string, not a date.
Calling intervalToDuration is expecting an interval object to be passed as the parameter. An interval consists of two Dates or Numbers (unix timestamp)
To correct this, you must convert endDate to a date object, below is an untested example;
const remaining = () => {
const endDate = "2021-02-26T00:00:00.000Z";
const now = new Date();
const end = new Date(endDate);
return intervalToDuration({
start: now,
end: end
});
};
const dur = remaining();
console.log("DURRATON ", JSON.stringify(dur));
//
// Response == DURRATON {"years":0,"months":1,"days":8,"hours":15,"minutes":42,"seconds":0}
//
Notice : This does not handle timezones correctly. new Date() will create a datetime in the client timezone where it appears that your response from the API is in GMT timezone
I have a UTC timestamp coming down from the server side. It's a static timestamp (for example: 11:30)
I want to convert 11:30 to users local timezone.
I did this:
const SessionStartTime = () => {
const startTime = moment.sessionStartTime
const convertTime = moment.utc(startTime).toDate()
const localTime = moment(convertTime)
console.log(localTime)
return <span>{new Date(startTime)}</span>
}
which converts the time to clients REAL-TIME which is not what I'm looking for.
Any tips?
edit:
After reading the docs I came up with this
const SessionStartTime = () => {
const dateFormat = "HH:mm"
const startTime = sessionStartTime
const localTime = startTime.local()
return <span>{localTime.format(dateFormat)}</span>
}
but it doesn't do anything.
I might be doing something silly here. But essentially, the time in Lisbon right now is 12:27 PM
but the following returns 14:27 (EU central time)
const time = moment.tz("Europe/Lisbon")
const timeZone = "Europe/Lisbon"
const format = "'HH[:]mm'"
const startMoment = moment.tz(item.startTime, format, timeZone);
const endMoment = moment(item.endTime, format, timeZone);
return time.isBetween(startMoment, endMoment);
I tried several combinations and I get the wrong answer everytime. For example if I set timeZone to be "Europe/Warsaw" it returns 15:27 whereas it should be 13:27.
EDIT: const currentTime = moment().tz("Europe/London").format() returns the correct time for London. However, the return statement moment(currentTime).isBetween(startMoment, endMoment) still reads "moment(correntTime)" as the local time.
isBetween return boolean . And isBetween runs on date object. You are trying to run on time zone object. which is different from date object
const time = moment.tz("Europe/Lisbon")
const timeZone = "Europe/Lisbon"
const format = "'HH[:]mm'"
const startMoment = moment().subtract(8, 'months').tz(timeZone).format();
const endMoment = moment(new Date()).tz(timeZone).format() ;
console.log("startMoment",startMoment)
console.log("endMoment",endMoment)
console.log(moment.tz(new Date(),"Europe/Lisbon").format())
console.log(moment('2020-09-30').isBetween(startMoment, endMoment));
<script src="https://momentjs.com/downloads/moment.min.js"></script>
<script src="https://momentjs.com/downloads/moment-timezone-with-data.js"></script>
So I'm troubleshooting with some JavaScript dates. I'm working with NodeJS Mongoose and React. I'd like to update all dates in database, but I'd like to do that every weekend and keep hours, don't change them at all.
Let say I have day like 22 January 2020, and during weekend date will update itself to 29 of January and then 5 of February. Everything in database is save like ISODate("2020-01-16T16:27:15.003Z") and I have a code to update those dates whenever I want. I'm having trouble figure out how to body of setDate() should look like to automatically change months and days while keeping the same hour everytime - so 22/01/2020 4:00 PM during weekend will change to 29/01/2020 4:00PM.
I've already tried to use momentjs to handle dates but it doesn't work with my database.
cron.schedule("* * * * * *",async function() {
const courses = await Course.find({});
courses.forEach(course => {
const newDate = () => {
let date = new Date();
return date.toISOString();
};
Course.updateMany({
"nextClasses": course.nextClasses === course.startingDate ? course.startingDate :
course.nextClasses
},{$set: {"nextClasses": newDate()}},(err) => console.log(err))
});
}
That's the code responsible for changing dates, for now it changes everything to current date every second ( on purpose, for validation purposes )
This would add 7 days to all dates every Sunday.
const addDays = (date, days) => {
const result = new Date(date);
result.setDate(result.getDate() + days);
return result;
};
cron.schedule("0 0 * * 0", async function() {
const courses = await Course.find({});
courses.forEach(async (course) => {
await course.update(
{
$set: {
nextClasses: addDays(course.nextClasses, 7)
}
},
(err) => console.log(err)
);
});
});
Alternate method
cron.schedule("0 0 * * 0", async function() {
const courses = await Course.find({});
courses.forEach(async (course) => {
course.nextClasses.setDate(course.nextClasses.getDate() + 7);
course.markModified("nextClasses"); /* Mongoose does not track changes made by built-in Date methods */
await course.save((err) => console.log(err));
});
});