Google Apps Script: Is a date part with a range - javascript

I would like to determine what season a date falls between. The date is in a cell and is not related to the current date.
I have gotten this far:
var myDate=myForm.getRange("C4").getValue();
if (Utilities.formatDate(myDate, "GMT", 'MM/dd')>'12/21' && Utilities.formatDate(myDate, "GMT", 'MM/dd')<'3/20'){
ui.alert("Winter")
}
I would repeat this obviously for other seasons.
My expectation is that 1/13/2023 evaluates to 1/13 by (Utilities.formatDate(myDate, "GMT", 'MM/dd') and falls with the range.
That is not happening
Thanks in advance.

Here is an example of comparing today's date with the season.
function getSeason() {
try {
// per Farmers Almanac
let season = ["Winter","Spring","Summer","Fall"];
let seasons = [["12/21/2021","3/20/2022","6/21/2022","9/22/2022","12/21/2022","3/20/2023"],
["12/21/2022","3/20/2023","6/21/2023","9/23/2023","12/21/2023","3/20/2024"],
["12/21/2023","3/19/2024","6/20/2024","9/22/2024","12/21/2024","3/20/2025"],
["12/21/2024","3/20/2025","6/20/2025","9/22/2025","12/21/2025","3/20/2026"],
["12/21/2025","3/20/2026","6/21/2026","9/22/2026","12/21/2026","3/20/2027"]];
let today = new Date();
let year = today.getFullYear()-2022;
today = new Date(today.getFullYear(),today.getMonth(),today.getDate());
let found = seasons[year].findIndex( (date,index) => {
return today >= new Date(date) && today < new Date(seasons[year][index+1]);
}
);
console.log(today);
console.log(season[found])
}
catch(err) {
console.log(err);
}
}
12:20:50 PM Notice Execution started
12:20:50 PM Info Mon Sep 12 2022 00:00:00 GMT-0700 (Pacific Daylight Time)
12:20:50 PM Info Summer
12:20:50 PM Notice Execution completed
Reference
Date object
Array.findIndex()

Season of the year:
function seasonOfTheYear(date) {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName("Sheet0");
const ds = sh.getDataRange().getValues();
const sObj = { pA: [] };
ds.forEach(s => {
sObj[new Date(s[1]).valueOf()] = { start: new Date(s[1]), season: s[0] };
sObj.pA.push(new Date(s[1]).valueOf());
});
let dv = new Date(date).valueOf();
let ssn = sObj.pA.reduce((a, c, i) => {
if (dv >= c && dv < sObj.pA[(i + 1) % sObj.pA.length]) {
a["season"] = sObj[c].season;
}
return a;
}, {season:''}).season;
Logger.log(ssn);
}
I got this data from timeandate.com and put it into Sheet0
A
B
SPRING
Tuesday, March 1
SUMMER
Wednesday, June 1
FALL
Thursday, September 1
WINTER
Thursday, December 1

Related

Find first monday date of month

I have a date (usually the first day of a month but not necessary, it could be any date) and I want a new date corresponding to the first Monday of that month.
example:
findFirstMonday('1 jul 2021') -> 7 jul 2021
findFirstMonday('1 aug 2021') -> 2 aug 2021
findFirstMonday('13 aug 2021') -> 2 aug 2021
Here is my code that doesn't work:
const selectedDate = new Date();
const daysInSelectedDate = daysInMonth(selectedDate);
const lastDayPreviousMonth = addDays(selectedDate, daysInSelectedDate - selectedDate.getDate() + 1);
const firstDayPreviousMonth = removeDays(
lastDayPreviousMonth,
daysInMonth(lastDayPreviousMonth),
);
console.log('firstDayPreviousMonth: ', firstDayPreviousMonth);
let firstMonday = firstDayPreviousMonth;
while (firstDayPreviousMonth.getDay() !== 1) {
console.log('firstMonday: ', firstMonday, firstMonday.getDay());
firstMonday.setDate(firstMonday.getDate() + 1);
}
console.log('firstMonday: ', firstMonday, firstMonday.getDay());
function addDays(date, days) {
const result = new Date(date)
result.setDate(result.getDate() + days)
return result
}
function removeDays(date, days) {
const result = new Date(date)
result.setDate(result.getDate() - days)
return result
}
function daysInMonth(date) {
return new Date(date.getFullYear(), date.getMonth(), 0).getDate()
}
What am I wrong?
Thanks a lot
I came up with the following code. Some explanations about the general idea:
For a given date get the first date in the month of the given date. This is quite easy by generating a new Date object with day = 1 and the year and month of the given date.
Get the weekday of the first date.
Depending on the weekday of the first date, you must calculate which day number the first Monday has. This number is calculated by ((8 - firstWeekdayInMonth) % 7). You can easily verify yourself, that this always yields a Monday. The modulo is important for Sundays and Mondays, where you would otherwise add 8 and 7 respectively, which would not yield the first Monday anymore.
console.log(findFirstMonday('1 jul 21'))
console.log(findFirstMonday('1 aug 21'))
console.log(findFirstMonday('13 aug 21'))
function findFirstMonday(dateString) {
let targetDate = new Date(dateString);
let targetMonth = targetDate.getMonth();
let targetYear = targetDate.getFullYear();
let firstDateInMonth = new Date(targetYear, targetMonth, 1);
let firstWeekdayInMonth = firstDateInMonth.getDay();
let firstMondayDate = 1 + ((8 - firstWeekdayInMonth) % 7);
return new Date(targetYear, targetMonth, firstMondayDate).toLocaleDateString();
}
Edit:
console.log(findFirstMondayMonth('1 jul 2021').toLocaleDateString())
console.log(findFirstMondayMonth('1 aug 2021').toLocaleDateString())
console.log(findFirstMondayMonth('2 aug 2021').toLocaleDateString())
console.log(findFirstMondayMonth('13 aug 2021').toLocaleDateString())
function findFirstMonday(dateString) {
let date = new Date(dateString)
let diffDay = date.getDay() - 1
if (diffDay == -1) {
diffDay = 6
}
let mondayDate = new Date(dateString);
mondayDate.setHours(mondayDate.getHours() - diffDay*24)
return mondayDate
}
function findFirstMondayMonth(dateString) {
let date = new Date(dateString)
if (date.getMonth() == findFirstMonday(date).getMonth()) {
let dateOneWeekBefore = new Date(dateString)
dateOneWeekBefore.setHours(dateOneWeekBefore.getHours() - 24 * 7)
if (date.getMonth() == dateOneWeekBefore.getMonth()) {
return findFirstMondayMonth(dateOneWeekBefore)
} else {
return findFirstMonday(date)
}
} else {
let dateOneWeekAfter = new Date(dateString)
dateOneWeekAfter.setHours(dateOneWeekAfter.getHours() + 24 * 7)
return findFirstMonday(dateOneWeekAfter)
}
}
Sorry for the last answer, I think it was the first monday of week and I don't see Sunday.getMonth() == -1

how to get all weekdays from a date range and duration

So i have an initialDate, a travelTime and a endDate,
we also have booleans representing the weekdays
lets say we whave the following:
initialDate = 06 Jun 2021
travelTime = 13:00 to 18:00
mon = true, tue = false, wed = true, thu: false, fri = false
endDate = initialDate + 1 month
i need to get all mondays and wednesday dates between initialDate and endDate
In this code bellow, using momentjs, I create two array, one for Mondays and one for Wednesdays formatted like you wrote the date in your question.
const dateFormatTemplate = 'DD MMM YYYY';
const initialDate = moment('06 Jun 2021', dateFormatTemplate);
const endDate = moment(initialDate).add(1, 'month');
const MONDAY = 1; // moment().day() return a value from 0 to 6(Sunday-to-Saturday)
const WEDNESDAY = 3;
const mondayArray = [];
const wednesdayArray = [];
while (initialDate.isSameOrBefore(endDate)) {
if (initialDate.day() === MONDAY) mondayArray.push(initialDate.format(dateFormatTemplate));
else if (initialDate.day() === WEDNESDAY) wednesdayArray.push(initialDate.format(dateFormatTemplate));
initialDate.add(1, 'day');
}
console.log('ALL MONDAY', mondayArray)
console.log('ALL WEDNESDAY', wednesdayArray);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>

date-fns Format Date and Age calculation problem in React

I was using "moment.js" in my project (like age calculator), but I want to replace it with "date-fns".
Using moment.js, I formatted the input value as DD / MM / YYYY (for TR) and was calculating the age by subtracting the current date but right now I am having trouble doing this with date-fns. I felt like moment.js came easier to use.
Moment.js age calculator codes: I entered the input on 10/03/1998. (DD/MM/YYYY -> Turkey)
const birthDay = moment(value, 'DD/MM/YYYY');
console.log(birthDay); // (output: 10/03/1998)
const now = moment();
console.log(now); // (output: Thu Mar 04 2021 10:40:09 // TR Local Time)
const age = moment.duration(now.diff(birthDay)).years();
console.log(age); // (output: 22)
I tried to do it with date-fns but was not successful. I can not calculate the age.
const birthDay = format(new Date(value), 'dd/MM/yyyy');
console.log(birthDay); // (output: 03/10/1998 - **issue 1**)
const now = new Date();
console.log(now); // (output: Thu Mar 04 2021 10:45:18 // TR Local Time)
const age = differenceInCalendarYears(now, birthDay);
console.log(age); // (output: NaN - - **issue 2**)
I would appreciate it if you could help with date-fns.
I edited for the answer, right now it's like this:
const birthDay = new Date(value);
console.log(birthDay); // Oct 03 1998 (03/10/1998) it's MM/DD, I want DD/MM
const now = new Date();
console.log(now); // Mar 04 2021
const age = differenceInCalendarYears(now, birthDay);
console.log(age); // it should be 22 but 23.
Your age depends on whether you had your anniversary on the current year. That's why you should NOT use differenceInCalendarYears to calculate the age: it does not take into account the current month and day, only the year.
Use differenceInYears instead, or intervalToDuration if you want to get the age including months and days.
const { differenceInCalendarYears, differenceInYears, intervalToDuration, parse } = require("date-fns")
function calculateAge(dob) {
const date = parse(dob, "dd/MM/yyyy", new Date());
const age = differenceInYears(new Date(), date);
return age;
}
// INCORRECT
function calculateAge2(dob) {
const date = parse(dob, "dd/MM/yyyy", new Date());
const age = differenceInCalendarYears(new Date(), date);
return age;
}
console.log("dob = 01/04/2000"); // Running on 2021-08-05
console.log('- using differenceInYears: ', calculateAge("01/04/2000")); // 21
console.log('- using differenceInCalendarYears: ', calculateAge2("01/04/2000")); // 21
console.log("dob = 01/10/2000"); // Running on 2021-08-05
console.log('- using differenceInYears: ', calculateAge("01/10/2000")); // 20
console.log('- using differenceInCalendarYears: ', calculateAge2("01/10/2000")); // 21
function calculateFullAge(dob) {
const birthDate = parse(dob, "dd/MM/yyyy", new Date());
const { years, months, days } = intervalToDuration({ start: birthDate, end: new Date()});
return { years, months, days };
}
// Running on 2021-08-05
console.log('- using intervalToDuration: ', calculateFullAge("01/04/2000")); // {years: 21, months: 4, days: 4}
console.log('- using intervalToDuration: ', calculateFullAge("01/10/2000")); // {years: 20, months: 10, days: 4}
You can run this in the following runkit
I recently had a similar situation & this is how I implemented it
import { differenceInYears, parse } from "date-fns"
const calculateAge = (dob: string): number => {
const date = parse(dob, "dd/MM/yyyy", new Date())
const age = differenceInYears(new Date(), date)
return age
}
calculateAge("11/11/2019") // returns 2
PS: consider removing types (:string & :number) if you're only using JS
Try this ;)
import { intervalToDuration } from "date-fns"
const calculateAge = (dob: string): number => {
const interval = intervalToDuration({
start: new Date(dob),
end: new Date(),
})
return interval.years ? interval.years : 0
}
Your problem is parsing the date string (timestamp) using:
const birthDay = new Date(value);
It's strongly recommended not to use the built–in parser, see Why does Date.parse give incorrect results?
Since you're using Date.fns, use it for parsing too.
And as #volpato points out, you should use differenceInYears not differenceInCalendarYears as the later is effectively just currentDate.getFullYear() - birthday.getFullYear():
let dateFns = require("date-fns")
let d = '10/03/1998'; // 10 Mar 1998
let date = dateFns.parse(d, 'dd/MM/yyyy', new Date());
let age = dateFns.differenceInYears(new Date(), date);
console.log(age); // 23 when run on 4 Mar 2021
The above can be run at npm.runkit.com

How to list all month between 2 dates with moment.js?

I've two dates
2015-3-30 2013-8-31
How can I make a month list like:
[ '2015-3', '2015-2', '2015-1', '2014-12', '2014-11', '2014-10', '2014-09', '2014-08', '2014-07', '2014-06', '2014-05'....., '2013-08' ]
Thanks.
This should do it:
var startDate = moment('2021-12-31');
var endDate = moment('2022-12-14');
var betweenMonths = [];
if (startDate < endDate){
var date = startDate.startOf('month');
while (date < endDate.endOf('month')) {
betweenMonths.push(date.format('YYYY-MM'));
date.add(1,'month');
}
}
I think the original answer isn't entirely correct, as you wouldn't get '2015-3' in your array. This is due to the fact your start date would eventually end up as '2015-3-31' and would fail the conditional in place. You could extend it like below.
UPDATE: I've now included cloning the dateStart variable so it isn't mutated at all.
var dateStart = moment('2013-8-31');
var dateEnd = moment('2015-3-30');
var interim = dateStart.clone();
var timeValues = [];
while (dateEnd > interim || interim.format('M') === dateEnd.format('M')) {
timeValues.push(interim.format('YYYY-MM'));
interim.add(1,'month');
}
You could try with this example
var one = moment("2015-3-30");
var two = moment("2014-8-31");
var dateDiffs = [];
var count = Math.round(moment.duration(one.diff(two)).asMonths());
month = two.month() + 1;
year = two.year();
for (var i=1; i<=count; i++) {
if (month > 12) {
month = 1;
year++;
}
dateDiffs.push(year+"-"+month);
console.log(month);
month++;
}
console.log(dateDiffs);
You are using multiple formats in the output: YYYY-MM and YYYY-M, so I picked the first. You can edit as you see fit.
var startDateString = "2012-5-30";
var endDateString = "2015-8-31";
var startDate = moment(startDateString, "YYYY-M-DD");
var endDate = moment(endDateString, "YYYY-M-DD").endOf("month");
var allMonthsInPeriod = [];
while (startDate.isBefore(endDate)) {
allMonthsInPeriod.push(startDate.format("YYYY-MM"));
startDate = startDate.add(1, "month");
};
console.log(allMonthsInPeriod);
document.getElementById("result").innerHTML = allMonthsInPeriod.join("<br />");
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.19.4/moment.min.js"></script>
<div id="result"></div>
const getMonths = (start, end) =>
Array.from({ length: end.diff(start, 'month') + 1 }).map((_, index) =>
moment(start).add(index, 'month').format('MM.YYYY'),
);
const months = getMonths(moment('01.2019','MM.YYYY'),moment('01.2020','MM.YYYY'))
console.log(months)
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.19.4/moment.min.js"></script>
This is the best way in my opinion.
const startDate = moment('2013-8-31', 'YYYY-M-DD');
const endDate = moment('2015-3-30', 'YYYY-M-DD');
const months = [];
const flag = startDate;
while (flag.diff(endDate) <= 0) {
months.push(flag.format('YYYY-M'));
flag.add(1, 'M');
}
Why don't you just https://date-fns.org/v2.13.0/docs/eachMonthOfInterval ??
// Each month between 6 February 2014 and 10 August 2014:
var result = eachMonthOfInterval({
start: new Date(2014, 1, 6),
end: new Date(2014, 7, 10)
})
//=> [
// Sat Feb 01 2014 00:00:00,
// Sat Mar 01 2014 00:00:00,
// Tue Apr 01 2014 00:00:00,
// Thu May 01 2014 00:00:00,
// Sun Jun 01 2014 00:00:00,
// Tue Jul 01 2014 00:00:00,
// Fri Aug 01 2014 00:00:00
// ]

Working with Javascript dates, getting 0 or above 31

I am using this code to generate 5 dates for my 'calendar' from the current week:
var days = new Array(4);
GetDaysOfWeek(new Date());
function GetDaysOfWeek(date)
{
for (var i = 0; i < 5; i++)
{
var $dd = (date.getDate() - date.getDay() + 1 + i);
var $mm = date.getMonth()+1;
var $yyyy = date.getFullYear();
if($dd<10){$dd='0'+$dd}if($mm<10){$mm='0'+$mm}
days[i] = $dd+'/'+$mm+'/'+$yyyy;
}
}
However depending what date it is it can return 00/10/2013 or 32/10/2013 on some of my boxes. It seems the only one updating correct is the actual date I am on.
How would I update those 5 dates so I would get the correct dates instead of non exist dates.
Thanks in advance.
currentTimestamp = new Date().getTime()
currentDay = currentTimestamp-currentTimestamp%(24*60*60*1000)
for (var i = 1; i< 6; i++){
nextDay = new Date(currentDay + i*24*60*60*1000)
days[i] = nextDay.toString(); //specify the format yourself
}
Here's a somewhat shorter way of creating an array of the dates of 5 weekdays from a given date;
function weekdays(d){
// set date [d] (or today) to the sunday before
var d = (function(){
this.setDate(this.getDate()-(this.getDay()));
return this;
}).apply(d || new Date);
// create an Array with length 5 and map 5 dates starting
// from date [d] into it
return String(Array(5)).split(',')
.map(function(){
return new Date(this.setDate(this.getDate()+1));
}, d);
}
It returns the weekdays from the first monday before the date, or, if the given date is a sunday, the dates of the weekdays from the next week.
weekdays();
//=> [Mon Oct 21 2013 17:14:23 GMT+0200, ... ,Fri Oct 25 2013 17:14:23 GMT+0200]
weekdays(new Date('2013/10/06'));
//=> [Mon Oct 07 2013 00:00:00 GMT+0200, ..., Fri Oct 11 2013 00:00:00 GMT+0200]
See also: Mozilla DN on map
Maybe this jsfiddle is of use to you?

Categories