Related
My javascript is horrible, I am a C# dev but here we are. So I need to loop through every month between a start year and month to an end year and month.
The startMonth and startYear will always be 1 and 2010 respectively.
I have the following solution at the moment:
//Get the current year and month
let currentTime = new Date();
let currentYear = currentTime.getFullYear();
let currentMonth = currentTime.getMonth() + 1;
//Set starting year and month
let startYear = 2010;
let startMonth = 1;
//Loop through the years and months
for (let i = startYear; i <= currentYear; i++){
if (i === currentYear ){
for (let k = 1; k <= currentMonth; k++){
//Do work
}
} else {
for (let j = startMonth; j <= 12; j++){
//Do work
}
}
}
Does someone have a better solution? I feel like this is really clunky. I don't mind using third party packages so if moment or something will work then I'll use it.
Here is what you want :
const start = moment.utc('2018-12');
const end = moment.utc('2020-02');
const year = end.diff(start, 'years');
const month = end.diff(start, 'months')
console.log(start, end);
console.log(year, month);// 1 14
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.27.0/moment.min.js"></script>
First off, be aware that months run from 0 to 11 so January is 0 not 1!
JavaScript's Date class automatically handles "overflows". So for example a date
new Date(2010, 12, 1)
automatically becomes "January 1st, 2011".
This can be used to simply increment just the month of a date:
const currentDate = new Date(2010, 0, 1);
const endDate = new Date();
endMonth.setMonth(endMonth.getMonth() + 1);
while (currentDate.getFullYear() != endMonth.getFullYear() && currentDate.getMonth() != endMonth.getMonth()) {
// Do something
currentDate.setMonth(currentDate.getMonth() + 1);
}
(Watch out that is could result in an endless loop if the start date is already after the end date.)
Here is a slight improvement without adding a third party library:
//Get the current year and month
let currentTime = new Date();
let currentYear = currentTime.getFullYear();
let currentMonth = currentTime.getMonth() + 1;
//Set starting year and month
let startYear = 2010;
let startMonth = 1;
//Loop through the years and months
for (let i = startYear; i <= currentYear; i++){
for (let j = startMonth; j <= (i == currentYear ? currentMonth: 12); j++){
//Do work
}
}
I want to make an auto adaptation or generation of days of year, from Gregorian to Hijri.
I mean that you want to select or write the year as example:
select 2015:
Get all the days of 2015 in Gregorian and then its convert to Hijrim and present the list of hijri.
so you want to return to 2 list list1 gregoriad days list vs another list2 hijhri
I want this in JavaScript and using kendo-ui framework to view it.
Kendo UI only supports the Gregorian calendar. There don't seem to be plans to add any others.
You could use .NET to convert the date.
public string ConvertDateCalendar(DateTime DateConv, ECalenderTypes calendar, string DateLangCulture)
{
System.Globalization.DateTimeFormatInfo DTFormat;
DateLangCulture = DateLangCulture.ToLower();
/// We can't have the hijri date writen in English. We will get a runtime error
if (calendar == ECalenderTypes.Hijri && DateLangCulture.StartsWith("en-"))
{
DateLangCulture = "ar-sa";
}
/// Set the date time format to the given culture
DTFormat = new System.Globalization.CultureInfo(DateLangCulture, false).DateTimeFormat;
/// Set the calendar property of the date time format to the given calendar
switch (calendar)
{
case ECalenderTypes.Hijri:
DTFormat.Calendar = new System.Globalization.HijriCalendar();
break;
case ECalenderTypes.Gregorian:
DTFormat.Calendar = new System.Globalization.GregorianCalendar();
break;
default:
return "";
}
/// We format the date structure to whatever we want
DTFormat.ShortDatePattern = "dd/MM/yyyy";
return (DateConv.Date.ToString("f", DTFormat));
}
And then:
ConvertDateCalendar("01/01/2015", ECalenderTypes.Gregorian, "en-US");
ConvertDateCalendar("01/01/2015", ECalenderTypes.Hijri, "en-US");
JavaScript
function gmod(n,m){
return ((n%m)+m)%m;
}
function getDate(adjust){
var today = new Date();
if(adjust) {
adjustmili = 1000*60*60*24 * adjust;
todaymili = today.getTime() + adjustmili;
today = new Date(todaymili);
}
day = today.getDate();
month = today.getMonth();
year = today.getFullYear();
m = month+1;
y = year;
if(m<3) {
y -= 1;
m += 12;
}
a = Math.floor(y/100.);
b = 2-a+Math.floor(a/4.);
if(y<1583) b = 0;
if(y==1582) {
if(m>10) b = -10;
if(m==10) {
b = 0;
if(day>4) b = -10;
}
}
jd = Math.floor(365.25*(y+4716))+Math.floor(30.6001*(m+1))+day+b-1524;
b = 0;
if(jd>2299160){
a = Math.floor((jd-1867216.25)/36524.25);
b = 1+a-Math.floor(a/4.);
}
bb = jd+b+1524;
cc = Math.floor((bb-122.1)/365.25);
dd = Math.floor(365.25*cc);
ee = Math.floor((bb-dd)/30.6001);
day =(bb-dd)-Math.floor(30.6001*ee);
month = ee-1;
if(ee>13) {
cc += 1;
month = ee-13;
}
year = cc-4716;
wd = gmod(jd+1,7)+1;
iyear = 10631./30.;
epochastro = 1948084;
epochcivil = 1948085;
shift1 = 8.01/60.;
z = jd-epochastro;
cyc = Math.floor(z/10631.);
z = z-10631*cyc;
j = Math.floor((z-shift1)/iyear);
iy = 30*cyc+j;
z = z-Math.floor(j*iyear+shift1);
im = Math.floor((z+28.5001)/29.5);
if(im==13) im = 12;
id = z-Math.floor(29.5001*im-29);
var myRes = new Array(8);
myRes[0] = day; //calculated day (CE)
myRes[1] = month-1; //calculated month (CE)
myRes[2] = year; //calculated year (CE)
myRes[3] = jd-1; //julian day number
myRes[4] = wd-1; //weekday number
myRes[5] = id; //islamic date
myRes[6] = im-1; //islamic month
myRes[7] = iy; //islamic year
return myRes;
}
function writeHijriDate(adjustment) {
var wdNames = new Array("Ahad","Ithnin","Thulatha","Arbaa","Khams","Jumuah","Sabt");
var iMonthNames = new Array("Muharram","Safar","Rabi'ul Awwal","Rabi'ul Akhir", "Jumadal Ula","Jumadal Akhira","Rajab","Sha'ban", "Ramadan","Shawwal","Dhul Qa'ada","Dhul Hijja");
var iDate = getDate(adjustment);
var outputHijriDate = wdNames[iDate[4]] + ", " + iDate[5] + " " + iMonthNames[iDate[6]] + " " + iDate[7] + " AH";
return outputHijriDate;
}
Usage (converts current date):
writeHijriDate(1);
Hirji calendar is not supported with Kendo UI.
Thanks all
I found someone write a simple implementation for the Islamic calender(Hijri) in Javascript
http://xsoh.github.com/Hijri.js
its consist the convert from hijri to gregorian and Vice versaز
The conversion is very easy using Intl object (read more), as following:
a = new Date();
localeFormat= 'ar-SA-islamic-umalqura';
Intl.DateTimeFormat(localeFormat).format(a)
I have two date strings like this:
var startDate = '2012-04-01';
var endDate = '2014-11-01';
And I want to end up with an array of strings like this:
var dates = ['2012-04-01', '2012-05-01', '2012-06-01' .... '2014-11-01',];
So far this is what I've got, but it's pretty ugly:
var startDate = '2012-04-01';
var endDate = '2014-11-01';
var start = new Date(Date.parse(startDate));
var end = new Date(Date.parse(endDate))
var dates = [];
for (var i = start.getFullYear(); i < end.getFullYear() + 1; i++) {
dates.push(i + '-' + '-01');
}
console.log(dates);
Is there a better way? JSFiddle.
This should produce the desired output:
function dateRange(startDate, endDate) {
var start = startDate.split('-');
var end = endDate.split('-');
var startYear = parseInt(start[0]);
var endYear = parseInt(end[0]);
var dates = [];
for(var i = startYear; i <= endYear; i++) {
var endMonth = i != endYear ? 11 : parseInt(end[1]) - 1;
var startMon = i === startYear ? parseInt(start[1])-1 : 0;
for(var j = startMon; j <= endMonth; j = j > 12 ? j % 12 || 11 : j+1) {
var month = j+1;
var displayMonth = month < 10 ? '0'+month : month;
dates.push([i, displayMonth, '01'].join('-'));
}
}
return dates;
}
Just call it with your existing date format:
dateRange('2013-11-01', '2014-06-01')
// ["2013-11-01", "2013-12-01", "2014-01-01", "2014-02-01", "2014-03-01", "2014-04-01", "2014-05-01", "2014-06-01", "2014-07-01", "2014-08-01", "2014-09-01", "2014-10-01", "2014-11-01", "2014-12-01"]
You can also use the excellent moment.js library:
var startDate = moment('2012-04-01');
var endDate = moment('2014-11-01');
var result = [];
if (endDate.isBefore(startDate)) {
throw "End date must be greated than start date."
}
while (startDate.isBefore(endDate)) {
result.push(startDate.format("YYYY-MM-01"));
startDate.add(1, 'month');
}
JSFiddle
If loading an extra library isn't a problem, you could always try the awesome MomentJS.
Gives for very clean and powerful date manipulation.
var startDate = moment('2012-04-01');
var endDate = moment('2014-11-01');
var dates = [];
endDate.subtract(1, "month"); //Substract one month to exclude endDate itself
var month = moment(startDate); //clone the startDate
while( month < endDate ) {
month.add(1, "month");
dates.push(month.format('YYYY-MM-DD'));
}
console.log(dates);
JSFiddle here
const getMonths = (fromDate, toDate) => {
const fromYear = fromDate.getFullYear();
const fromMonth = fromDate.getMonth();
const toYear = toDate.getFullYear();
const toMonth = toDate.getMonth();
const months = [];
for(let year = fromYear; year <= toYear; year++) {
let monthNum = year === fromYear ? fromMonth : 0;
const monthLimit = year === toYear ? toMonth : 11;
for(; monthNum <= monthLimit; monthNum++) {
let month = monthNum + 1;
months.push({ year, month });
}
}
return months;
}
const sample = getMonths(new Date('2022-07-28'), new Date('2023-03-20'));
console.log(sample);
document.write('check the console output');
https://jsfiddle.net/xfayoqvs/
You are handling "logical" jumps, so you doesn't actually need timing arthmetics. So this is a simple counting problem:
var startDate = '2012-04-01';
var endDate = '2014-11-01';
var dates = [];
var d0 = startDate.split('-');
var d1 = endDate.split('-');
for (
var y = d0[0];
y <= d1[0];
y++
) {
for (
var m = d0[1];
m <= 12;
m++
) {
dates.push(y+"-"+m+"-1");
if (y >= d1[0] && m >= d1[1]) break;
};
d0[1] = 1;
};
console.log(dates);
Here is a solution which just uses string manipulation on that specific YYYY-MM-DD format:
function monthsBetween(...args) {
let [a, b] = args.map(arg => arg.split("-").slice(0, 2)
.reduce((y, m) => m - 1 + y * 12));
return Array.from({length: b - a + 1}, _ => a++)
.map(m => ~~(m / 12) + "-" + ("0" + (m % 12 + 1)).slice(-2) + "-01");
}
console.log(monthsBetween('2012-04-01', '2014-11-01'));
Here is another solution, using Date objects:
const enumerateMonths = (from, to) => {
const current = new Date(from)
current.setUTCDate(1)
current.setUTCHours(0, 0, 0, 0)
const toDate = new Date(to)
const months = []
while (current.getTime() <= toDate.getTime()) {
months.push(current.getUTCFullYear() + "-" + `${current.getUTCMonth() + 1}`.padStart(2, "0"))
current.setUTCMonth(current.getUTCMonth() + 1)
}
return months
}
This solution presumes you provide Date objects or ISO 8601 strings. Please mind that an ISO 8601 date does not necessarily have to contain the hours-minutes-seconds part. "2012-01-14" is a valid ISO 8601 date.
An example to get all first days of months between a given date and now using moment.js.
var getMonths = function (startDate) {
var dates = [];
for (var year = startDate.year(); year <= moment().year(); year++) {
var endMonth = year != moment().year() ? 11 : moment().month();
var startMonth = year === startDate.year() ? startDate.month() : 0;
for (var currentMonth = startMonth; currentMonth <= endMonth; currentMonth = currentMonth > 12 ? currentMonth % 12 || 11 : currentMonth + 1) {
var month = currentMonth + 1;
var displayMonth = month < 10 ? '0' + month : month;
dates.push([year, displayMonth, '01'].join('-'));
}
}
return dates;
};
All solutions above run in O(n^2) time complexity, which is not very efficient.
See below solution in O(n) time complexity:
function getAllMonths(start, end){
let startDate = new Date(start);
let startYear = startDate.getFullYear();
let startMonth = startDate.getMonth()+1;
let endDate = new Date(end);
let endYear = endDate.getFullYear();
let endMonth = endDate.getMonth()+1;
let countMonth = 0;
let countYear = 0;
let finalResult = [];
for(let a=startYear; a<=endYear; a++){
if(startYear<endYear){
if(countYear==0){
countMonth += 12-startMonth;
}else
if(countYear>0){
countMonth += 12;
}
countYear+=1;
startYear++;
}else
if(startYear==endYear){
countMonth+=endMonth;
}
}
for(let i=startMonth; i<=countMonth+startMonth; i++){
finalResult.push(startDate.getFullYear()+(Math.floor(i/12)) + "-" + Math.round(i%13) + "-" + "01");
}
return finalResult;
}
getAllMonths('2016-04-01', '2018-01-01');
Might share a much more simpler code
Still not a very elegant answer, but arrives at the array of strings you want:
var startDate = '2012-04-01';
var endDate = '2014-11-01';
var start = new Date(startDate);
var end = new Date(endDate);
var dates = [];
for (var i = start.getFullYear(); i < end.getFullYear() + 1; i++) {
for (var j = 1; j <= 12; j++) {
if (i === end.getFullYear() && j === end.getMonth() + 3) {
break;
}
else if (i === 2012 && j < 4){
continue;
}
else if (j < 10) {
var dateString = [i, '-', '0' + j, '-','01'].join('');
dates.push(dateString)
}
else {
var dateString = [i, '-', j, '-','01'].join('');
dates.push(dateString);
}
}
}
console.log(dates);
jsfiddle link here: http://jsfiddle.net/8kut035a/
This is my solution, with help of math and O(n)
determineMonthInInterval(startDate, endDate) {
let startYear = startDate.getFullYear();
let endYear = endDate.getFullYear();
let startMonth = startDate.getMonth() + 1;
let endMonth = endDate.getMonth() + 1;
let monthAmount = (endMonth - startMonth) + 1 + (12 * (endYear - startYear));
let dates = [];
let currMonth = startMonth;
let currYear = startYear;
for( let i=0; i<monthAmount; i++){
let date = new Date(currYear + "/"+currMonth+"/1");
dates.push(date);
currYear = startYear + Math.floor((startMonth+i) / 12);
currMonth = (currMonth) % 12 +1;
}
return dates;
}
Here is another option:
getRangeOfMonths(startDate: Date, endDate: Date) {
const dates = new Array<string>();
const dateCounter = new Date(startDate);
// avoids edge case where last month is skipped
dateCounter.setDate(1);
while (dateCounter < endDate) {
dates.push(`${dateCounter.getFullYear()}-${dateCounter.getMonth() + 1}`);
dateCounter.setMonth(dateCounter.getMonth() + 1);
}
return dates;
}
From JavaScript is there a way to get list of days between two dates from MySQL format. I don't want to use any library for this.
This is what i did.
function generateDateList(from, to) {
var getDate = function(date) { //Mysql Format
var m = date.getMonth(), d = date.getDate();
return date.getFullYear() + '-' + (m < 10 ? '0' + m : m) + '-' + (d < 10 ? '0' + d : d);
}
var fs = from.split('-'), startDate = new Date(fs[0], fs[1], fs[2]), result = [getDate(startDate)], start = startDate.getTime(), ts, end;
if ( typeof to == 'undefined') {
end = new Date().getTime();
} else {
ts = to.split('-');
end = new Date(ts[0], ts[1], ts[2]).getTime();
}
while (start < end) {
start += 86400000;
startDate.setTime(start);
result.push(getDate(startDate));
}
return result;
}
console.log(generateDateList('2014-2-27', '2014-3-2'));
I test it from chrome and nodejs below are the result.
[ '2014-02-27',
'2014-02-28',
'2014-02-29',
'2014-02-30',
'2014-02-31',
'2014-03-01',
'2014-03-02' ]
yeh big leap year:-D..., how can i fix this? or is there any better way.?
const listDate = [];
const startDate ='2017-02-01';
const endDate = '2017-02-10';
const dateMove = new Date(startDate);
let strDate = startDate;
while (strDate < endDate) {
strDate = dateMove.toISOString().slice(0, 10);
listDate.push(strDate);
dateMove.setDate(dateMove.getDate() + 1);
};
Take the start date and increment it by one day until you reach the end date.
Note: MySQL dates are standard format, no need to parse it by hand just pass it to the Date constructor: new Date('2008-06-13').
const addDays = (date, days = 1) => {
const result = new Date(date);
result.setDate(result.getDate() + days);
return result;
};
const dateRange = (start, end, range = []) => {
if (start > end) return range;
const next = addDays(start, 1);
return dateRange(next, end, [...range, start]);
};
const range = dateRange(new Date("2014-02-27"), new Date("2014-03-02"));
console.log(range);
console.log(range.map(date => date.toISOString().slice(0, 10)))
Here I use a recursive function, but you could achieve the same thing using a while (see other answers).
I have used this one from
https://flaviocopes.com/how-to-get-days-between-dates-javascript/
const getDatesBetweenDates = (startDate, endDate) => {
let dates = []
//to avoid modifying the original date
const theDate = new Date(startDate)
while (theDate < new Date(endDate)) {
dates = [...dates, new Date(theDate)]
theDate.setDate(theDate.getDate() + 1)
}
dates = [...dates, new Date(endDate)]
return dates
}
Invoke the function as follows:
getDatesBetweenDates("2021-12-28", "2021-03-01")
Note - I just had to fix issues with the Date object creation (new Date()) in the while loop and in the dates array. Other than that the code is pretty much same as seen on the above link
dateRange(startDate, endDate) {
var start = startDate.split('-');
var end = endDate.split('-');
var startYear = parseInt(start[0]);
var endYear = parseInt(end[0]);
var dates = [];
for(var i = startYear; i <= endYear; i++) {
var endMonth = i != endYear ? 11 : parseInt(end[1]) - 1;
var startMon = i === startYear ? parseInt(start[1])-1 : 0;
for(var j = startMon; j <= endMonth; j = j > 12 ? j % 12 || 11 : j+1) {
var month = j+1;
var displayMonth = month < 10 ? '0'+month : month;
dates.push([i, displayMonth, '01'].join('-'));
}
}
return dates;
}
var oDate1 = oEvent.getParameter("from"),
oDate2 = oEvent.getParameter("to");
var aDates = [];
var currentDate = oDate1;
while (currentDate <= oDate2) {
aDates.push(new Date(currentDate));
currentDate.setDate(currentDate.getDate() + 1);
}
I expanded Công Thắng's great answer to return {years, months, days}, thought it was worth sharing:
function getDates(startDate, endDate) {
const days = [],
months = new Set(),
years = new Set()
const dateMove = new Date(startDate)
let date = startDate
while (date < endDate){
date = dateMove.toISOString().slice(0,10)
months.add(date.slice(0, 7))
years.add(date.slice(0, 4))
days.push(date)
dateMove.setDate(dateMove.getDate()+1) // increment day
}
return {years: [...years], months: [...months], days} // return arrays
}
console.log(getDates('2016-02-28', '2016-03-01')) // leap year
/* =>
{
years: [ '2016' ],
months: [ '2016-02', '2016-03' ],
days: [ '2016-02-28', '2016-02-29', '2016-03-01' ]
}
*/
const {months} = getDates('2016-02-28', '2016-03-01') // get only months
Basically the function just increments the built-in Date object by one day from start to end, while the Sets capture unique months and years.
Hopefully someone can help.
I have the following function to return the last 6 monthly names (I.E June, July, August etc), however, I cannot work out how I would then use each returned month name as separate variables.
I need this so I can feed each month name in to an sql query that populates a table for the last 6 months.
Any help much appreciated.
function getMonths()
{
var today = new Date();
var month = 1;
var currMonth = month-3;
var monthArray = new Array("January","February","March","April","May","June",
"July","August","September","October","November","December");
var menuMonths = new Array();
var count = 6;
var buffer = 10;
while(count >0)
{
if (currMonth < 0)
currMonth += 12;
if (currMonth >=12 )
currMonth -= 12;
var month = monthArray[currMonth];
menuMonths.push(month);
currMonth = currMonth -1;
count = count -1;
}
return (menuMonths.reverse());
}
console.log (getMonths());
You can use Array.slice()
FIDDLE http://jsfiddle.net/BeNdErR/NF5Qm/1/
CODE
var monthArray = new Array("January","February","March","April","May","June",
"July","August","September","October","November","December");
var currMonth = 3; // the current month index, from 1 to 12
var firstMonth = currMonth - 6;
if(firstMonth < 0){ //for example if currMonth is January - 0
var months = [];
months.push(monthArray.slice(12 - Math.abs(firstMonth), 12));
months.push(monthArray.slice(0, currMonth));
alert(months);
}else{
alert(monthArray.slice(firstMonth, currMonth))
}
As output, you still have an array, so you can pass it to the SQL Query as it is, for example (SQLite):
tx.executeSql("SELECT * FROM tablename WHERE month = ? OR month = ? month = ? OR month = ? month = ? OR month = ?;", [slicedMonthArray], successCB, errorCB);
Hope it helps
var months = getMonths();
for(var i=0, len=months.length; i<len; i++){
var currentMonth = months[i];
alert(currentMonth);
//do whatever you want here;
}