I'm currently populating a table with data from a soap web service, the date comes as a string (example 44250). I created a function to format it into a yyyy/mm/dd format.
Outside the loop I have this function:
Date.prototype.addDays = function (days) {
var date = new Date(this.valueOf());
date.setDate(date.getDate() + days);
return date;
};
Inside the loop I have:
else if (detailsItem == details[i].children[1].innerHTML) {
const dbDays = days[i].innerHTML;
const daysInt = parseInt(dbDays, 0);
const newDate = firstDate.addDays(daysInt);
// Format the date to a readable value
const partsDate = {
date: newDate.getDate(),
month: newDate.getMonth() + 1,
year: newDate.getYear() + 1900,
};
finalDate = `${partsDate.date}/${partsDate.month}/${partsDate.year}`;
const td = document.createElement("td");
td.textContent = finalDate;
tr.appendChild(td);
}
the else if is just checking when to add the date to the table while populating it.
I now need to send a request to the service using the date again but in the previous format, but the date has to be in the same row as the button click, the service only accepts the string format of the date, I'm currently stuck and unsure on how to format it back.
This is the button click function which has to then format the date back to a format such as 44250.
btn.onclick = function () {
// Loops through the table to find the slot and date when clicking the button on the same row
var tableRow = document.getElementById("booking-table"),
rIndex;
for (var i = 0; i < tableRow.rows.length; i++) {
tableRow.rows[i].onclick = function () {
rIndex = this.rowIndex;
bookingDay = this.cells[1].innerHTML;
bookingSlot = this.cells[2].innerHTML;
console.log(bookingSlot, bookingDay);
};
}
Any help on how to accomplish this would be appreciated.
The value "44250" looks like the number of days since 31 Dec 1899 (the epoch), which means a value of "1" converts to 1 Jan 1900. If that's correct, you can create a Date from it using:
let dbDays = '44250';
let date = new Date(1900, 0, dbDays); // 24 Feb 2021
In this algorithm, 1 is 1 Jan 1900 and 0 is 31 Dec 1899.
You can convert it back to an epoch offset using the reverse algorithm:
let dbDays = Math.round((date.getTime() - new Date(1899, 11, 31) / 8.64e7);
Which gets the difference in ms since the date and the epoch, then divides by ms in one day and rounds it to account for possible daylight saving effects where days aren't exactly 24 hours long. This method only works for whole days, it doesn't work for partial days.
The algorithm might be out by a day if 1 Jan 1900 should be 0 rather than 1, just adjust the base dates used in the functions.
Simple functions to go from dbDate to Date instance and back are:
// Convert epoch days to Date
function toDate(dbDays) {
return new Date(1900, 0, +dbDays);
}
// Convert Date to epoch days
function toDBDays(date) {
return Math.round((date - new Date(1899,11,31)) / 8.64e7);
}
// Format date as dd/mm/yyyy
function formatDate(d) {
let z = n => ('0'+n).slice(-2);
return z(d.getDate()) + '/' + z(d.getMonth()+1) + '/' + d.getFullYear();
}
// Parse date in d/m/y format, any non-digit separator
function parseDate(s) {
let [d,m,y] = s.split(/\D/);
return new Date(y, m - 1, d)
}
// Example
let dbDays = '44250';
let d1 = toDate(dbDays); // 24 Feb 2021
let ts = formatDate(d1); // 24/02/2021
let d2 = parseDate(ts); // date object
console.log(dbDays + ' to Date: ' + ts);
console.log(ts + ' to dbDays: ' + toDBDays(d2));
PS Given the epoch won't change, instead of creating a date for 31 Dec 1899 and getting its time value, the constant -2209111200000 can be used.
Notes on your code:
const daysInt = parseInt(dbDays, 0);
The second argument to parseInt is a radix or base to use for conversion to number. The value 0 is replaced with 10 (the default radix), so the above is equivalent to:
const daysInt = parseInt(dbDays, 10);
Then there is:
const partsDate = {
date: newDate.getDate(),
month: newDate.getMonth() + 1,
year: newDate.getYear() + 1900,
};
The getYear method returns a 2 digit year, it's not recommended and is supported mostly for historic reasons, use getFullYear instead.
Using an object for temporary storage is not really optimal, just use variables:
let date = newDate.getDate(),
month = newDate.getMonth() + 1,
year = newDate.getFullYear();
Note that this doesn't pad single digit days or months with leading zeros so will produce timestamps like 1/1/2021 instead of 01/01/2021.
You can use momentjs to convert the date easier: https://momentjs.com/ ,
about the use of the date after you pass that value to the html, can you store that value on some global variable,sesion or localstorage? and then use it later? to call again the soap service? i'm asumming your working on a web page, cause your using html :)
Related
I have to create two ISO date strings in an Array based on the long month name.
Input: 'August'
Output: ['2020-08-01T00:00:00', '2020-08-31T00:00:00']
I am thinking about a switch case to check for each month but I am not sure how to create the ISO string with this information. I could match August with 08 and replace a pre-defined ISO string and replace it based on the input but this doesn't sound very clever.
You can get the month names from toLocaleString for the locale you are in or hardcode an array.
Then calculate the first of this month and the 0th of NEXT month
I had to normalise the time to 15:00 to handle timezones.
const yyyy = new Date().getFullYear();
const months = Array.from(Array(12).keys())
.map(month => new Date(yyyy, month, 5, 15, 0, 0, 0)
.toLocaleString('default', { month: 'long'}) );
const zeroTime = str => `${str.split("T")[0]}T00:00:00`;
const getDates = month => {
const monthNum = months.indexOf(month);
const start = new Date(yyyy, monthNum, 1, 15, 0, 0, 0),
end = new Date(yyyy, monthNum+1, 0, 15, 0, 0, 0)
return [zeroTime(start.toISOString()), zeroTime(end.toISOString())];
};
console.log(getDates("August"))
There are many ways to go about this, the only real issue is how to generate the list of month names. The following uses mplungian's approach of generating them in the browser default language, though I'm not sure that's a good idea.
The other part of the problem is to generate timestamps for the start and end of the month. That's pretty simple given a year and month number. You can use UTC values and toISOString, then trim the trailing Z to get local timestamps.
The following should be efficient as it only generates one date and array to get the month names, then one more of each on each call of getMonthDates. It also uses for loops instead of creating arrays and using array methods for iteration.
It also provides separate functions for getting the month number from the name and dates from month number and year. They use ECMAScript month number (0 = Jan, etc.) but could easily be converted to use calendar month number (1 = Jan, etc.).
// Given year and ECMAScript month number, return an array of ISO 8601
// formatted local timestamps for first and last days of the month
let getMonthDates = (monthNum = 0, year = new Date().getFullYear()) => {
let date = new Date(Date.UTC(year, monthNum));
let start = date.toISOString().substring(0, 19);
date.setUTCMonth(monthNum + 1, 0);
return [start, date.toISOString().substring(0, 19)];
}
// Given a month name, return it's ECMAScript month number
// Uses host default language for month name
let getMonthDatesFromName = (() => {
let date = new Date();
let monthNames = (() => {
date.setMonth(0, 1);
for (var arr=[], i=0; i<12; i++) {
arr.push(date.toLocaleString('default',{month:'long'}));
date.setMonth(i+1)
}
return arr;
})();
return (monthName, year) => {
let monthNum = monthNames.indexOf(monthName);
// If month name not found, return undefined
return monthNum < 0? void 0 : getMonthDates(monthNum, year);
}
})();
/** getMonthDatesFromName examples
*/
// Undefined if month name not valid
console.log('foo: ' + getMonthDatesFromName('foo'));
// Current month name
let monthName = new Date().toLocaleString('default',{month: 'long'});
console.log(monthName + ': ' + getMonthDatesFromName(monthName).toString());
// February, 2024
console.log('February, 2024: ' + getMonthDatesFromName('February', 2024).toString());
/** getMonthDates examples
*/
// January of current year by default
console.log('Default: ' + getMonthDates().toString());
// Month of current year by default, e.g. for April
console.log('April: ' + getMonthDates(3).toString());
// Month and year - February 2024
console.log('1, 2024: ' + getMonthDates(1, 2024).toString());
I am trying to pass string variable to JS date object and create date in future.
Its easy to do in this way:
var d = new Date();
var year = d.getFullYear();
var month = d.getMonth();
var day = d.getDate();
var my_date = new Date(year + 1, month +1, day +1);
But how I can pass it with string variable, so that I can achieve something like this:
var d = new Date();
var year = d.getFullYear();
var month = d.getMonth();
var day = d.getDate();
var my_variable = 'year + 1, month +1, day +1';
var my_date = new Date(my_variable);
In this case it returns Invalid date
Note
You need to be a little careful with date arithmetic since it's not symmetric and may give odd results, e.g. 29 Feb 2016 + 1 year gives 1 March 2017, and 31 July minus 1 month is 1 July since there is no 31 June, it rolls over to July, and so on.
Given your original requirement, you might consider a parser for your particular format, e.g.
function myParse(s, date) {
date = date || new Date();
// Default values object
var values = {
year:{sign:1, value:0}, month:{sign:1, value:0}, day:{sign:1, value:0}
};
// Tokenise string
var part = s.toLowerCase().match(/[a-z]+|\d+|[+-]/ig);
// Process the tokens
if (part) {
for (var i=0, iLen=part.length; i<iLen; i++) {
if (part[i] in values) {
values[part[i]].sign = part[i+1] == '+'? 1 : -1;
values[part[i]].value = +part[i+2];
i += 2;
}
}
}
// Apply to date
date.setFullYear(
date.getFullYear() + values.year.sign * values.year.value,
date.getMonth() + values.month.sign * values.month.value,
date.getDate() + values.day.sign * values.day.value
);
return date;
}
// Examples
var options = {day:'2-digit',month:'short',year:'numeric'};
console.log('Today is ' + (new Date().toLocaleString('en-gb', options)));
['year+1,month+1,day+1', // one of each
'year+2,day+2', // missing parameters
'day + 15, month +2', // any order, random whitespace
'month - 3' // subtraction
].forEach(function(s) {
console.log(s + '\n' + myParse(s).toLocaleString('en-gb', options));
});
It's fairly tolerant but you should validate the input. It could be extended to handle time too, and also the end of month issues noted above.
Unfortunately javascript (and all the languages that I know off hand) do not work like that.
You could use an eval statement instead, which allows you to create the entire instruction as a string and run that string...
var my_variable = 'year + 1, month +1, day +1';
eval('var my_date = new Date(' + my_variable + ');');
HOWEVER using of eval is dangerous, and could open you up to unexpected attacks. Only use it if absolutely necessary, and if you're sure that the string being used is "safe"
You are inserting Javascript code as a string, which makes no sense to the Date class.
You can have your variables stored in an array to pass them elegantly to Date.
const dates = [year + 1, month +1, day +1]
const my_date = new Date(...dates);
I've read a follow up comment which indicates you'll only be getting strings from wherever you are retrieving the data from. Firstly if the string is in the format of 'year + 1, month + 1, day + 1', it'll never make sense to the Date object. If the string is just 3 numbers separated by a comma, you could split the string at the commas and pass them to the Date object in the same fashion.
const dates = myString.split(',');
const my_date = new Date(...dates);
I have some code, that is doing pretty much all i need it to do. Its calculating 3 days in the future, excluding dates, and then displaying my "estimated dispatch date"
The date, however displays in full date and time, instead of just date.
Day Month Date Year 12:02:57 GMT+0100 (British Summer Time)
Can anyone help with the code below, so that it excludes local time and only displays the future date, excluding weekend, DD/MM/YYYY or, in the below format;
Monday 20th June
Thanks in advance!
function addDates(startDate,noOfDaysToAdd){
var count = 0;
while(count < noOfDaysToAdd){
endDate = new Date(startDate.setDate(startDate.getDate() + 1));
if(endDate.getDay() != 0 && endDate.getDay() != 6){
//Date.getDay() gives weekday starting from 0(Sunday) to 6(Saturday)
count++;
}
}
return startDate;
}
var today = new Date();
var daysToAdd = 3;
document.write ('Estimated Dispatch Date: ' + addDates(today,daysToAdd));
You can use the toDateString method to display just the date portion of your Date object, but you will need to use a few other methods for full control over the format of your date string...
You can display just the date, month and year parts of your local date and time with a few extra lines of code using the getDate, getMonth, and getFullYear methods to help with the formatting. You could try passing specific formatting parameters to toLocaleString, but this may display different results in different browsers. For example, the code below outputs a date in the format dd/mm/yyyy in Chrome but that output is not guaranteed across browsers.
new Date().toLocaleString('en-GB', {year: 'numeric', month: 'numeric', day: 'numeric'})
Not sure I am following how you want to handle weekend dates, so the below handles the date formatting that you want in the formatDate function separately from the addDays function where it just handles weekend dates by rolling the date forward to a Monday if the initially calculated date lands on a Saturday or Sunday.
// format input date to dd/mm/yyyy
const formatDate = (date) => {
const d = date.getDate(); // day of the month
const m = date.getMonth(); // month index from 0 (Jan) to 11 (Dec)
const yyyy = date.getFullYear(); // 4 digit year
const dd = (d < 10 ? '0' : '') + d; // format date to 2 digit
const mm = (m + 1 < 10 ? '0' : '') + (m + 1); // convert index to month and format 2 digit
return `${dd}/${mm}/${yyyy}`;
};
// add input days to today and adjust for weekend output
const addDays = (today, days) => {
const now = today.getTime() // now in UTC milliseconds
const ms = 24 * 60 * 60000; // milliseconds in one day
const date = new Date((days * ms) + now); // today plus input days
const day = date.getDay(); // weekday index from 0 (Sun) to 6 (Sat)
// adjust weekend results to next weekday
if (day === 0 || day === 6) {
let adj = day === 0 ? 1 : 2;
return new Date(((days + adj) * ms) + now);
}
return date;
};
document.write('Estimated Dispatch Date: ' + formatDate(addDays(new Date(), 3)));
I have a string that looks like "01:12:33" which is HH:MM:SS format. How can I convert that to a time value in JS?
I've tried the new Date() constructor and setting the year and day values to 0, then doing getTime(), but I am not having any lucky.
Prefix it with a date:
var hms = "01:12:33";
var target = new Date("1970-01-01T" + hms);
console.log(target);
There target.getTime() will give you the number of milliseconds since the start of the day;
Or, if you need it to be today's date:
var now = new Date();
var nowDateTime = now.toISOString();
var nowDate = nowDateTime.split('T')[0];
var hms = '01:12:33';
var target = new Date(nowDate + 'T' + hms);
console.log(target);
There target.getTime() will give you the number of milliseconds since the epoch.
You can add the following function that does the job for you :
function getDateFromHours(time) {
time = time.split(':');
let now = new Date();
return new Date(now.getFullYear(), now.getMonth(), now.getDate(), ...time);
}
console.log(getDateFromHours('01:12:33'));
To be able to do this, there should be a conversion of the string in HH:MM:SS format to JavaScript time.
Firstly, we can use Regular Expression (RegEx) to properly extract the values in that string.
let timeString = "01:12:33";
Extract values with RegEx
let regExTime = /([0-9]?[0-9]):([0-9][0-9]):([0-9][0-9])/;
let regExTimeArr = regExTime.exec(timeString); // ["01:12:33", "01", "12", "33", index: 0, input: "01:12:33", groups: undefined]
Convert HH, MM and SS to milliseconds
let timeHr = regExTimeArr[1] * 3600 * 1000;
let timeMin = regExTimeArr[2] * 60 * 1000;
let timeSec = regExTimeArr[3] * 1000;
let timeMs = timeHr + timeMin + timeSec; //4353000 -- this is the time in milliseconds.
In relation to another point in time, a reference time has to be given.
For instance,
let refTimeMs = 1577833200000 //Wed, 1st January 2020, 00:00:00;
The value above is is the number of milliseconds that has elapsed since the epoch time (Jan 1, 1970 00:00:00)
let time = new Date (refTimeMs + timeMs); //Wed Jan 01 2020 01:12:33 GMT+0100 (West Africa Standard Time)
I'm working on a form that needs to automatically calculate the day the form is being submitted in the format ('MMDDYYYY'), and then on the click of one of two links a link, calculate the closest first day of the coming month, and the closest 15th day of the coming month.
I already created a script that pulls in the date and outputs it to a variable in the format I need, but I need help in calculating the roll forward.
Here's an example of the logic I'm thinking I need:
If the current date is 04092013, on a the button press labeled "Coming 1st of Month" a variable value of 05012013 would be calculated.
If the current date is 04092013, on a button press labeled "Coming 15th of Month" a variable value of 04152013 would be calculated.
If the current date is 04162013 or any date up to the end of the current month, on a button press labeled "Coming 15th of Month" a variable value of 05152013 would be calculated.
Look at the Date object, it should provide what you need:
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date
For example something like this for your first 2 buttons:
$(function() {
var date = new Date(2013, 10, 24);
$("#date").html(date.toString());
$("#date1").html((new Date(date.getYear(), date.getMonth()+1, 1)).toString());
$("#date2").html((new Date(date.getYear(), date.getMonth()+1, 15)).toString());
});
(Though I'm sure there are easier ways to do this if you look through the Date documenation)
Here is an example. If you want it back as a string, you'll have to format it at the end as desired (work with UTC ).
If you put in a date that has the same day number as you're asking of it, it returns the same day, not moving forwards a month.
var date_string = '04092013';
// MMDDYYYY
function nextNthOfMonth(date_string, n) {
var date;
// n to Int, default 1
n = (+n || 1);
// date_string to ISO 8601
date_string = // "yyyy-MM-ddTHH:mm:ssZ"
date_string.slice(4)
+ '-' + date_string.slice(0, 2)
+ '-' + date_string.slice(2, 4)
+ 'T00:00:00Z';
// construct date object
date = new Date(date_string);
// fix to desired date
if (n < date.getUTCDate()) { // adjust for month if req.
date.setUTCMonth(date.getUTCMonth() + 1);
}
date.setUTCDate(n);
return date; // or format as desired
}
nextNthOfMonth(date_string, 1);
// Wed May 01 2013 01:00:00 GMT+0100 (GMT Daylight Time)
nextNthOfMonth(date_string, 15);
// Mon Apr 15 2013 01:00:00 GMT+0100 (GMT Daylight Time)
Since you know the format of your date, split the input into parts:
var dateStr = '04092013'
var month = dateStr.substr(0,2);
var day = dateStr.substr(2,2);
var year = dateStr.substr(4,4);
The construct a new date base on the rule you want to set:
var newDate;
switch(rule)
{
case 'rule1':
newDate = new Date(year, month, 1);//first month is 0
break;
case 'rule2':
newDate = new Date(year, month, 15);//first month is 0
break;
}
remember to check if the day is greater that 15.
Try
function getDate() {
var s = document.getElementById('date').value;
if(s){
return new Date(s.substring(4), parseInt(s.substring(2, 4), 10) - 1, s.substring(0, 2))
}
}
function comingDate(date, day){
date = new Date(date);
var cday = date.getDate();
date.setDate(day);
if(cday >= day){
date.setMonth(date.getMonth() + 1)
}
return date
}
function f15(){
var d = getDate();
var next = comingDate(d, 15);
console.log(next)
}
function f1(){
var d = getDate();
var next = comingDate(d, 1);
console.log(next)
}
Demo: Fiddle