I'm trying to figure out how to check if a specific DateTime is within a time interval. For example, let's say I have a variable named dateTimeToCheck and I want to see if it is within the first quarter of the year (Jan 1st to March 31st).
I could use diff between dateTimeToCheck and Jan 1st and then diff between dateTimeToCheck and March 31st followed by some calculations, but I feel like there should be a cleaner way using Luxon's Interval or something like that.
Any help is very much appreciated!
Yes, you can use Luxon's Interval. The API has the contains method that:
Return whether this Interval contains the specified DateTime.
Here an example where I've used fromDateTimes to create Interval object:
const DateTime = luxon.DateTime;
const Interval = luxon.Interval;
const interval = Interval.fromDateTimes(DateTime.local(2023, 1, 1), DateTime.local(2023, 3, 31));
let dateTimeToCheck = DateTime.now();
console.log(interval.contains(dateTimeToCheck));
<script src="https://cdn.jsdelivr.net/npm/luxon#3.2.1/build/global/luxon.min.js"></script>
Related
I have a date selector and a time selector, and I'm trying to figure out how I can combine their outputs to make a single ISOString so that I can use with the google calendar API.
Here's what I've tried:
//date = 2022-05-18
//time = 14:22
const apptdate = new Date(date)
const timeSplit = time.split(':')
apptDate.setHours(timeSplit[0])
apptDate.setMinutes(timeSplit[1])
What I notice is when I console.log(apptdate) this is the output I get: 2022-05-17T18:22:00.000Z
I'm not sure why it changes the day from May 18 to May 17, and the time from 14:22 to 18:22.
Does anyone have a solution for this? Or even a completely different way of combining date and time to one string (other than using a datetime-local input format, I want to keep the date and time separate in my database).
"2022-05-18" is parsed as UTC but apptDate.setHours(timeSplit[0]) sets the local hour. So if the host has a negative offset, the local date is 17 May and the time is set to the local hour on 17 May, not UTC hour on 18 May.
Instead use setUTCHours and setUTCMinutes.
let date = '2022-05-18';
let time = '14:22';
let apptDate = new Date(date);
let timeSplit = time.split(':');
apptDate.setUTCHours(timeSplit[0]);
apptDate.setUTCMinutes(timeSplit[1]);
// 2022-05-18T14:22:00.000Z
console.log(apptDate.toISOString());
PS. There was also a typo: let apptdate then later apptDate.
I'm trying to obtain the Duration (or start and end dates) of an arbitrary 'quarter' in Luxon.
For example, suppose I want the beginning and ending dates of the 3rd quarter knowing only the quarter:
const quarterInQuestion = 3;
const startDateOfQuarter = DateTime.fromFormat(quarterInQuestion.toString(), 'q');
This will give me the start date of the quarter, but how can I obtain the end date as well. I've looked into Durations and Intervals but can't seem to get anything to work yet.
Many thanks!
I think you want the endOf method, to which you can pass the period that you want the end of from a date.
const startDateOfQuarter = DateTime.fromFormat('3', 'q');
const endDateOfQuarter = startDateOfQuarter.endOf('quarter')
I use moment.js to display a UTC date in the users local timezone:
var date = new Date(Date.UTC(2016,03,30,0,0,0));
var now = new Date();
var diff = (date.getTime()/1000) - (now.getTime()/1000);
var textnode = document.createTextNode(moment(date).format('dddd, DD.MM.YYYY') + ' a las ' + moment(date).format('HH:mm A'));
document.getElementsByClassName("date")[0].appendChild(textnode.cloneNode(true));
I later use the diff variable to show a countdown timer.
I would like to show a different countdown timer to everyone in their local time zone. (Using the difference till its midnight in their time zone, not in UTC)
But I am struggeling to get it work. Instead of using var date = new Date(Date.UTC(2016,03,30,0,0,0)); I probably need to use some function of moment.js that gives me till midnight in the users time zone.
The best example would be new years eve. If I use UTC everyone would have the same counter (9 hours left) but in different parts of the world this wouldn't make sense. For someone in australia it should be 2 hours left, and for someone in the US 14 hours.
I'm not sure that I fully understand your question, but I'll give you some general advice and tips.
When using moment.js, there is very little need to ever use the Date object. Only use it for interacting with other APIs that expect a Date object.
To get a moment in UTC, just use moment.utc(...), passing the appropriate arguments, such as moment.utc([2016,3,30]) or moment.utc('2016-04-30') for midnight April 30th UTC.
If you want to convert that back to the user's local time, use the .local() function. For example, moment.utc('2016-04-30').local() will create a moment with the equivalent local time to the UTC time provided.
If you want a moment in the user's local time, then that would be moment(...), such as moment([2016,3,30]) or moment('2016-04-30') for midnight April 30th local time.
You can difference two moments using the diff function, which can give the answer in specific units, such as m1.diff(m2, 'seconds') where m1 and m2 are moment objects.
You don't need to call format twice. Just encapsulate any text you want outputed with square brackets. .format('dddd, DD.MM.YYYY [a las] HH:mm A')
You might look into moment's locale support. If I'm not mistaken, "a las" indicates Spanish, however it's not always "a las", but sometimes "a la", if the hour is 1. Also, moment only uses those words in its .calendar() function, such as when producing a phrase like "mañana a las 13:17". A regular date formatted with .format('LLLL') in the Spanish locale would be something like: "sábado, 19 de marzo de 2016 13:17". So, you might want to verify that "a las" is exactly what you want in every case.
The title to this question was how to set a date to midnight. For that, I recommend using moment's startOf function. m.startOf('day') will give set the moment m to the start of the day, which is usually midnight. Keep in mind that not every local day actually starts at midnight in every time zone. Due to anomalies like daylight saving time, some days might start at 1:00. For example, this occurs in Brazil on October 16th this year.
Also, if you created the moment in UTC mode, you may wish to convert it back to local mode first before setting it to the start of the day. If you don't want to change the original moment object, be sure to clone it first.
Putting this all together:
var m1 = moment.utc([2016,3,30]);
var m2 = m1.clone().local().startOf('day');
var now = moment();
var diff = m1.diff(now, 'seconds');
I'm trying to get from a time formatted Cell (hh:mm:ss) the hour value, the values can be bigger 24:00:00 for example 20000:00:00 should give 20000:
Table:
if your read the Value of E1:
var total = sheet.getRange("E1").getValue();
Logger.log(total);
The result is:
Sat Apr 12 07:09:21 GMT+00:09 1902
Now I've tried to convert it to a Date object and get the Unix time stamp of it:
var date = new Date(total);
var milsec = date.getTime();
Logger.log(Utilities.formatString("%11.6f",milsec));
var hours = milsec / 1000 / 60 / 60;
Logger.log(hours)
1374127872020.000000
381702.1866722222
The question is how to get the correct value of 20000 ?
Expanding on what Serge did, I wrote some functions that should be a bit easier to read and take into account timezone differences between the spreadsheet and the script.
function getValueAsSeconds(range) {
var value = range.getValue();
// Get the date value in the spreadsheet's timezone.
var spreadsheetTimezone = range.getSheet().getParent().getSpreadsheetTimeZone();
var dateString = Utilities.formatDate(value, spreadsheetTimezone,
'EEE, d MMM yyyy HH:mm:ss');
var date = new Date(dateString);
// Initialize the date of the epoch.
var epoch = new Date('Dec 30, 1899 00:00:00');
// Calculate the number of milliseconds between the epoch and the value.
var diff = date.getTime() - epoch.getTime();
// Convert the milliseconds to seconds and return.
return Math.round(diff / 1000);
}
function getValueAsMinutes(range) {
return getValueAsSeconds(range) / 60;
}
function getValueAsHours(range) {
return getValueAsMinutes(range) / 60;
}
You can use these functions like so:
var range = SpreadsheetApp.getActiveSheet().getRange('A1');
Logger.log(getValueAsHours(range));
Needless to say, this is a lot of work to get the number of hours from a range. Please star Issue 402 which is a feature request to have the ability to get the literal string value from a cell.
There are two new functions getDisplayValue() and getDisplayValues() that returns the datetime or anything exactly the way it looks to you on a Spreadsheet. Check out the documentation here
The value you see (Sat Apr 12 07:09:21 GMT+00:09 1902) is the equivalent date in Javascript standard time that is 20000 hours later than ref date.
you should simply remove the spreadsheet reference value from your result to get what you want.
This code does the trick :
function getHours(){
var sh = SpreadsheetApp.getActiveSpreadsheet();
var cellValue = sh.getRange('E1').getValue();
var eqDate = new Date(cellValue);// this is the date object corresponding to your cell value in JS standard
Logger.log('Cell Date in JS format '+eqDate)
Logger.log('ref date in JS '+new Date(0,0,0,0,0,0));
var testOnZero = eqDate.getTime();Logger.log('Use this with a cell value = 0 to check the value to use in the next line of code '+testOnZero);
var hours = (eqDate.getTime()+ 2.2091616E12 )/3600000 ; // getTime retrieves the value in milliseconds, 2.2091616E12 is the difference between javascript ref and spreadsheet ref.
Logger.log('Value in hours with offset correction : '+hours); // show result in hours (obtained by dividing by 3600000)
}
note : this code gets only hours , if your going to have minutes and/or seconds then it should be developped to handle that too... let us know if you need it.
EDIT : a word of explanation...
Spreadsheets use a reference date of 12/30/1899 while Javascript is using 01/01/1970, that means there is a difference of 25568 days between both references. All this assuming we use the same time zone in both systems. When we convert a date value in a spreadsheet to a javascript date object the GAS engine automatically adds the difference to keep consistency between dates.
In this case we don't want to know the real date of something but rather an absolute hours value, ie a "duration", so we need to remove the 25568 day offset. This is done using the getTime() method that returns milliseconds counted from the JS reference date, the only thing we have to know is the value in milliseconds of the spreadsheet reference date and substract this value from the actual date object. Then a bit of maths to get hours instead of milliseconds and we're done.
I know this seems a bit complicated and I'm not sure my attempt to explain will really clarify the question but it's always worth trying isn't it ?
Anyway the result is what we needed as long as (as stated in the comments) one adjust the offset value according to the time zone settings of the spreadsheet. It would of course be possible to let the script handle that automatically but it would have make the script more complex, not sure it's really necessary.
For simple spreadsheets you may be able to change your spreadsheet timezone to GMT without daylight saving and use this short conversion function:
function durationToSeconds(value) {
var timezoneName = SpreadsheetApp.getActive().getSpreadsheetTimeZone();
if (timezoneName != "Etc/GMT") {
throw new Error("Timezone must be GMT to handle time durations, found " + timezoneName);
}
return (Number(value) + 2209161600000) / 1000;
}
Eric Koleda's answer is in many ways more general. I wrote this while trying to understand how it handles the corner cases with the spreadsheet timezone, browser timezone and the timezone changes in 1900 in Alaska and Stockholm.
Make a cell somewhere with a duration value of "00:00:00". This cell will be used as a reference. Could be a hidden cell, or a cell in a different sheet with config values. E.g. as below:
then write a function with two parameters - 1) value you want to process, and 2) reference value of "00:00:00". E.g.:
function gethours(val, ref) {
let dv = new Date(val)
let dr = new Date(ref)
return (dv.getTime() - dr.getTime())/(1000*60*60)
}
Since whatever Sheets are doing with the Duration type is exactly the same for both, we can now convert them to Dates and subtract, which gives correct value. In the code example above I used .getTime() which gives number of milliseconds since Jan 1, 1970, ... .
If we tried to compute what is exactly happening to the value, and make corrections, code gets too complicated.
One caveat: if the number of hours is very large say 200,000:00:00 there is substantial fractional value showing up since days/years are not exactly 24hrs/365days (? speculating here). Specifically, 200000:00:00 gives 200,000.16 as a result.
I have been reading up on dates for days, seemingly going in circles here. I have a string in a DB that looks like this
2012,03,13,01,31,38
I want to create a js date object from it so...
new Date(2012,03,13,01,31,38);
Easy enough, right? But it comes back as
2012-04-13 05:31:38 +0000
So the month is off by 1 and the time is off by 4 hours (maybe DST or Timezone related???). I simply want a date that matches the one I provided. Its driving me nuts, dealing with these JS date objects.
How can I be sure the date object is the exact same date and time as the string suggests, I have no need for Timezone or DST changes, simply a date that matches a string.
More specifics regarding application:
My application for this need is for an iphone app I am developing in Titanium (which builds using JS). Basically, part of my app involves logging data and with that log I collect the device's current date and time. I save all of this information to a mySQL database. The field in the database looks like this format: "2012-02-16 00:12:32"
Here is where I start to run into problems. I am now offering the ability to edit the log, including the date and time it was logged. In order to use an iPhone "picker", I must convert the string above into a JS date object again. This usually screws things up for me. I essentially need to create a new date object with the date above, with timezone and dst being completely irrelevant, so that when I save back to the DB, its just the string above, modified as per the users request. It needs to not matter whether they are editing in pennsylvania or china, they are editing the same log date.
Sorry if this has been confusing. I am having a hard time figuring out this whole date stuff.
This depends on what your string is. If that string is UTC time, you need to parse it as that. If it's local time, you need to parse it as local time. You can make a helper method like this for that part:
function getDate(utc, year, month, day, hour, minute, second) {
if(utc) {
var utc = Date.UTC(year, month - 1, day, hour, minute, second);
return new Date(utc);
} else {
return new Date(year, month - 1, day, hour, minute, second);
}
}
Now, to parse your string, you can use this:
function fromString(utc, str) {
var parts = str.split(',');
var year = parts[0];
var month = parts[1];
var day = parts[2];
var hour = parts[3];
var minute = parts[4];
var second = parts[5];
return getDate(utc, year, month, day, hour, minute, second);
}
which you can use like this for your example:
var d = fromString(true, '2012,02,13,00,31,38'); // If UTC
var d = fromString(false, '2012,02,13,00,31,38'); // If local time
Here's a working jsFiddle that you can play with:
http://jsfiddle.net/rNqXW/
which also shows two ways to print the date (UTC or local). Hope this helps.
I had the same problem. There are two reasons for the weird time change:
Use new Date(Date.UTC(2012,03,13,01,31,38)) to avoid the time change.
Note that the month is zero based! Months go from 0 to 11 for this function.