Strange Javascript Problem Involving split("/"); - javascript

Okay, so using the following function:
function date_add(date, days)
{
var dim = {1:31, 2:28, 3:31, 4:30, 5:31, 6:30, 7:31, 8:31, 9:30, 10:31, 11:30, 12:31};
console.log(date.split("/"));
var date_arr = date.split("/");
console.log(date_arr);
...
}
I get the following output at the console screen for date_add("12/08/1990", 1)
["12", "08", "1990"]
["2", "08", "1990"]
Spending an hour struggling with what could fix this weird problem, on a whim I changed my function to the following:
function date_add(date, days)
{
var dim = {1:31, 2:28, 3:31, 4:30, 5:31, 6:30, 7:31, 8:31, 9:30, 10:31, 11:30, 12:31};
date = date.split("/");
console.log(date);
...
}
Magically, the code works again. Now don't get me wrong, I'm ecstatic that it worked. I'm seriously concerned over why it worked, though, when the other didn't. More or less I'm just concerned with why the other didn't work. Does anyone have a good explanation?
Edit: Now they're both broken. >.>
For Tomas, here is the full function:
function date_add(date, days)
{
var dim = {1:31, 2:28, 3:31, 4:30, 5:31, 6:30, 7:31, 8:31, 9:30, 10:31, 11:30, 12:31};
console.log(date);
console.log(date.split("/"));
date_arr = date.split("/");
console.log(date)
if (date_arr[0][0] = "0") date_arr[0] = date_arr[0][1];
if (date_arr[1][0] = "0") date_arr[1] = date_arr[1][1];
var month = parseInt(date_arr[0]);
var day = parseInt(date_arr[1]);
var year = parseInt(date_arr[2]);
console.log(month);
console.log(day);
console.log(year);
if ((year%4 == 0 && year%100 != 0) || year%400 == 0)
dim[2] = 29;
day += days;
while (day < 1)
{
month--;
if (month < 1)
{
month = 12;
year--;
}
day += dim[month];
}
while (dim[month] < day)
{
day -= (dim[month]+1);
month++;
if (month > 12)
{
month = 0;
year++;
}
}
return ""+month+"/"+day+"/"+year;
}
As for the input for the function, I called this function from the console using date_add('12/08/1990',1);

The problem with your original code is most probably you were not using the second parameter for your parseInt() calls, which is to specify the base for which you want to convert to, by default it assumes a 10 base, but when the number starts with zero as in your 08 case, then it assumes its an octal number, so the solution is to use the second parameter in your parseInt calls, like this:
var month = parseInt(date_arr[0], 10);
var day = parseInt(date_arr[1], 10);
var year = parseInt(date_arr[2], 10);
This behaviour have been fixed in last versions of javascript (EcmaScript 5), see this question for more info:
How do I work around JavaScript's parseInt octal behavior?

Related

Throw an error when month is not in between 1 -12

So I'm trying to verify a date of bith with the following code and I am having trouble implementing the if statements that check to see if month is greater than 12, it should throw an error and if day is greater than 31 it should also do the same. I would highly appreciate your help.
function isYearCorrect(string) {
let dateOfBirth = new Date((string.substring(0, 2)), (string.substring(2, 4) - 1), (string.substring(4, 6)))
let year = dateOfBirth.getFullYear();
let month = dateOfBirth.getMonth() + 1;
let day = dateOfBirth.getDate();
let isDOBValid = false;
if (month < 10) {
month = "0" + month;
}
/**This statement does not check to see if the month ranges from 1 - 12 but it skips
to the next year and month and leaves the day as is. Basically 971315 becomes 1998-01-15*/
if (month > 12) {
return (`${month} is an invalid month`)
} else {
month;
}
if (day < 10) {
day = "0" + day;
} if (day > 31) {
return (`${day} is an invalid month`);
}else {
day;
}
let fullDate = `${year}-${month}-${day}`;
let dateRegex = /^([12]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01]))$/;
if (dateRegex.test(fullDate) == false) {
isDOBValid;
} else if (dateRegex.test(fullDate) == true) {
isDOBValid = true;
}
return isDOBValid;
}
console.log(isYearCorrect("970812"))
console.log(isYearCorrect("721329"))
You need to put your validation checks conditions before converting the string to the date.
function isYearCorrect(string) {
let yearPiece = +string.substring(0, 2);
let monthPiece = +string.substring(2, 4);
let dayPiece = +string.substring(4, 6);
if (monthPiece > 12) {
return (`${monthPiece} is an invalid month`)
}
if (dayPiece > 31) {
return (`${dayPiece} is an invalid month`);
}
let dateOfBirth = new Date(yearPiece, monthPiece, dayPiece)
let year = dateOfBirth.getFullYear();
let month = dateOfBirth.getMonth() + 1;
let day = dateOfBirth.getDate();
let isDOBValid = false;
/**This statement does not check to see if the month ranges from 1 - 12 but it skips
to the next year and month and leaves the day as is. Basically 971315 becomes 1998-01-15*/
if (month < 10) {
month = "0" + monthPiece;
}
if (day < 10) {
day = "0" + day;
}
let fullDate = `${year}-${month}-${day}`;
let dateRegex = /^([12]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01]))$/;
if (dateRegex.test(fullDate)) {
isDOBValid = true;
}
return isDOBValid;
}
console.log(isYearCorrect("970812"))
console.log(isYearCorrect("721329"))
TLDR: It works as designed.
The solution is to parse the string before putting this into new Date constructor, because what you are trying to do is somehow already done by Date object.
What is happening is that Date is "clever" and it prevents from invalid dates and triggers inner mechanisms, so that when you for example call this function with value "721429" which is supposed to be invalid, you get as a result "1973-3-1". Which is correct (keep in mind February is shorter).
Here you can read more about a date itself and it's acceptable constructors:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/Date
What is more - I suggest not to use "string" as a name of variable and use const where it's possible (e.g. regex or fullDate variable).

How to calculate the last friday of the month with momentjs

How could I calculate the last friday of this month using the momentjs api?
Correct answer to this question:
var lastFriday = function () {
var lastDay = moment().endOf('month');
if (lastDay.day() >= 5)
var sub = lastDay.day() - 5;
else
var sub = lastDay.day() + 2;
return lastDay.subtract(sub, 'days');
}
The previous answer returns the next to last friday if the last day of the month is friday.
Given a moment in the month you want the last Friday for:
var lastFridayForMonth = function (monthMoment) {
var lastDay = monthMoment.endOf('month').startOf('day');
switch (lastDay.day()) {
case 6:
return lastDay.subtract(1, 'days');
default:
return lastDay.subtract(lastDay.day() + 2, 'days');
}
},
E.g.
// returns moment('2014-03-28 00:00:00');
lastFridayForMonth(moment('2014-03-14));
Sorry guys but I tested previous answers and all of them are wrong.
Check all of them for
moment([2017,2])
And you will find that the result is incorrect.
I wrote this solution which is working so far:
let date = moment([2017,2]).endOf('month');
while (date.day() !== 5) {
date.subtract(1,'days')
}
return date;
Shorter answer :
var lastFridayForMonth = function (monthMoment) {
let lastDay = monthMoment.endOf('month').endOf('day');
return lastDay.subtract((lastDay.day() + 2) % 7, 'days');
}
I tried testing multiple months and for few months above answer by #afternoon did not work. Below is the test code.(one such test is for Aug 2018)
var moment = require('moment')
var affirm = require("affirm.js")
var cc = moment(Date.now())
for (var i = 0; i < 100000; i++) {
lastFridayForMonth(cc)
var nextWeek = moment(cc).add(7, 'days')
console.log(cc.format("ddd DD MMM YYYY"), nextWeek.format('MMM'))
affirm((cc.month() - nextWeek.month()) === -1 || (cc.month() - nextWeek.month()) === 11, "1 month gap is not found")
affirm(cc.day() === 5, "its not friday")
cc.add(1, "months")
}
I have put another solution
function lastFridayForMonth(monthMoment) {
var month = monthMoment.month()
monthMoment.endOf("month").startOf("isoweek").add(4, "days")
if (monthMoment.month() !== month) monthMoment.subtract(7, "days")
}

Moment.js how to get week of month? (google calendar style)

I am using Moment.js and it is great. The problem I have now is that I can't figure out how to get the week of the month a certain date is. I can only find "week of year" in the Moment js docs. For example, if I choose today's date (2/12/2014), I would like to know that this date is in the second week of this month of february and consequently, it is the second wednesday of the month. Any ideas?
EDIT:
I guess some clarification is necessary. What I need most is the nth number of a certain day in a month. For example, (from the comments) Feb 1, 2014 would be the first Saturday of the month. Feb 3, 2014 would be the first Monday of the month even though it is "technically" the second week of the month. Basically, exactly how google calendar's repeat function classifies days.
It seems that moment.js does not have the method that implements the functionality that you are looking for.
However, you can find the nth number of a certain day of the week in a month is using the Math.ceil of the date / 7
For example:
var firstFeb2014 = moment("2014-02-01"); //saturday
var day = firstFeb2014.day(); //6 = saturday
var nthOfMoth = Math.ceil(firstFeb2014.date() / 7); //1
var eightFeb2014 = moment("2014-02-08"); //saturday, the next one
console.log( Math.ceil(eightFeb2014.date() / 7) ); //prints 2, as expected
It looks like this is the number you are looking for, as demonstrated by the following test
function test(mJsDate){
var str = mJsDate.toLocaleString().substring(0, 3) +
" number " + Math.ceil(mJsDate.date() / 7) +
" of the month";
return str;
}
for(var i = 1; i <= 31; i++) {
var dayStr = "2014-01-"+ i;
console.log(dayStr + " " + test(moment(dayStr)) );
}
//examples from the console:
//2014-01-8 Wed number 2 of the month
//2014-01-13 Mon number 2 of the month
//2014-01-20 Mon number 3 of the month
//2014-01-27 Mon number 4 of the month
//2014-01-29 Wed number 5 of the month
When calculating the week of the month based on a given date, you have to take the offset into account. Not all months start on the first day of the week.
If you want to take this offset into account, you can use something something like the following if you are using moment.
function weekOfMonth (input = moment()) {
const firstDayOfMonth = input.clone().startOf('month');
const firstDayOfWeek = firstDayOfMonth.clone().startOf('week');
const offset = firstDayOfMonth.diff(firstDayOfWeek, 'days');
return Math.ceil((input.date() + offset) / 7);
}
Simple using moment.js
function week_of_month(date) {
prefixes = [1,2,3,4,5];
return prefixes[0 | moment(date).date() / 7]
}
This library adds the function moment.weekMonth()
https://github.com/c-trimm/moment-recur
I made some modifications based on feedback.
let weeks = moment().weeks() - moment().startOf('month').weeks() + 1;
weeks = (weeks + 52) % 52;
On days passing through the next year, the week value will be negative so I had to add 52.
What about something like:
weekOfCurrentMonth = (moment().week() - (moment().month()*4));
This takes the current week of the year, and subtracts it by the 4 times the number of previous months. Which should give you the week of the current month
I think the answer to this question will be helpful, even though it doesn't use moment.js as requested:
Get week of the month
function countWeekdayOccurrencesInMonth(date) {
var m = moment(date),
weekDay = m.day(),
yearDay = m.dayOfYear(),
count = 0;
m.startOf('month');
while (m.dayOfYear() <= yearDay) {
if (m.day() == weekDay) {
count++;
}
m.add('days', 1);
}
return count;
}
There is a problem with #Daniel Earwicker answer.
I was using his function in my application and the while loop was infinite because of the following situation:
I was trying to figure out which week of december (2016) was the day 31.
the first day of december was day 336 of the year. The last day of december was day 366 of the year.
Problem here: When it was day 366 (31 of december, last day of the year) the code added another day to this date. But with another day added it would be day 1 of january of 2017. Therefore the loop never ended.
while (m.dayOfYear() <= yearDay) {
if (m.day() == weekDay) {
count++;
}
m.add('days', 1);
}
I added the following lines to the code so the problem would be fixed:
function countWeekdayOccurrencesInMonth(date) {
var m = moment(date),
weekDay = m.day(),
yearDay = m.dayOfYear(),
year = m.year(),
count = 0;
m.startOf('month');
while (m.dayOfYear() <= yearDay && m.year() == year) {
if (m.day() == weekDay) {
count++;
}
m.add('days', 1);
}
return count;
}
It verifies if it is still in the same year of the date being veryfied
Here's Robin Malfait's solution implemented with the lightweight library date-fns
import {
differenceInDays,
startOfMonth,
startOfWeek,
getDate
} from 'date-fns'
const weekOfMonth = function (date) {
const firstDayOfMonth = startOfMonth(date)
const firstDayOfWeek = startOfWeek(firstDayOfMonth)
const offset = differenceInDays(firstDayOfMonth, firstDayOfWeek)
return Math.ceil((getDate(date) + offset) / 7)
}
export default weekOfMonth
I'd do the following:
let todaysDate = moment(moment.now());
let endOfLastMonth = moment(get(this, 'todaysDate')).startOf('month').subtract(1, 'week');
let weekOfMonth = todaysDate.diff(endOfLastMonth, 'weeks');
That gets todaysDate and the endOfLastMonth and then uses Moment's built-in diff() method to compute the current month's week number.
It's not built-in, but basically you can subtract the week number of the start of the month from the week number of the date in question.
function weekOfMonth(m) {
return m.week() - moment(m).startOf('month').week() + 1;
}
Credit goes to code by original author, give him a star if it helped you.
How about this?
const moment = require("moment");
// Generate Week Number of The Month From Moment Date
function getWeekOfMonth(input = moment()) {
let dayOfInput = input.clone().day(); // Saunday is 0 and Saturday is 6
let diffToNextWeek = 7 - dayOfInput;
let nextWeekStartDate = input.date() + diffToNextWeek;
return Math.ceil((nextWeekStartDate) / 7);
}
Simple code, but has been working for me.
const weekOfTheMonth = (myMomentDate) => {
const startDay = moment(myMomentDate).startOf('week');
const day = parseInt(startDay.format('DD'),10);
if(day > 28){
return 5;
}
if((day > 21) && (day <= 28) ){
return 4;
}
if((day > 14) && (day <= 21) ){
return 3;
}
if((day > 7) && (day <= 14) ){
return 2;
}
return 1;
}

Adding setUTCDate() to replace "computers" time

I followed this tutorial, but I wanted to just be able to set a date and have it countdown to that date.
Even so, it would just base it off my computer's time; how can I make it so it's standard for everyone?
He mentioned setUTCDate() but I have no idea how to implement it?
Here's some code to get you started. It gets the UTC time and alert's it, formatted:
// By default, JS does not pad times with zeros
function checkTime(i) {
if(i<10) i='0'+i;
return i;
}
// Set current UTC time
var d = new Date();
var now = checkTime(d.getUTCHours()) + ':' +
checkTime(d.getUTCMinutes()) + ':' +
checkTime(d.getUTCSeconds());
// Output
alert(now);
Here's a JSFiddle.
Remember: UTC != GMT (read on if you want this to always match the UK time).
BST (when the clocks go forward) will need to be factored in for anyone in the UK wanting to use this solution.
Here's a function I wrote earlier:
// Function returning 0 or 1 depending on whether BST is in effect
function isBSTinEffect()
{
var d = new Date();
// Loop over the 31 days of March for the current year
for(var i=31; i>0; i--)
{
var tmp = new Date(d.getFullYear(), 2, i);
if(tmp.getDay() == 0) { lSoM = tmp; break; }
}
// Loop over the 31 days of October for the current year
for(var i=31; i>0; i--)
{
var tmp = new Date(d.getFullYear(), 9, i);
if(tmp.getDay() == 0) { lSoO = tmp; break; }
}
if(d < lSoM || d > lSoO) return 0;
else return 1;
}
To factor in BST, put that function before // Set current UTC time and change checkTime(d.getUTCHours()) to checkTime(d.getUTCHours()+isBSTinEffect())

How to detect the user's locale date and time format

Is there a possibility to determine, with pure Javascript, what date time FORMAT has user configured on his operating system (Windows, Linux, MAC OS, etc.)?
Thanks in advance.
EDIT: I know about the method toLocaleString(), but this isn't help me to get the format that client has configured on his local machine.
I wrote something in pure javascript that works in IE/Firefox/Chrome. It will out put MM/DD/YYYY or DD/MM/YYYY,... depending in toLocalDateString().
Did not work on Safari but new Date().toLocalDateString() did not either.
Here is a jsFiddle
//Create a known date string
var y = new Date(2013, 9, 25);
var lds = y.toLocaleDateString();
//search for the position of the year, day, and month
var yPosi = lds.search("2013");
var dPosi = lds.search("25");
var mPosi = lds.search("10");
//Sometimes the month is displayed by the month name so guess where it is
if(mPosi == -1)
{
mPosi = lds.search("9");
if(mPosi == -1)
{
//if the year and day are not first then maybe month is first
if(yPosi != 0 && dPosi != 0)
{
mPosi = 0;
}
//if year and day are not last then maybe month is last
else if((yPosi+4 < lds.length) && (dPosi+2 < lds.length)){
mPosi = Infinity;
}
//otherwist is in the middle
else if(yPosi < dPosi){
mPosi = ((dPosi - yPosi)/2) + yPosi;
}else if(dPosi < yPosi){
mPosi = ((yPosi - dPosi)/2) + dPosi;
}
}
}
var formatString="";
var order = [yPosi, dPosi, mPosi];
order.sort(function(a,b){return a-b});
for(i=0; i < order.length; i++)
{
if(order[i] == yPosi)
{
formatString += "YYYY/";
}else if(order[i] == dPosi){
formatString += "DD/";
}else if(order[i] == mPosi){
formatString += "MM/";
}
}
formatString = formatString.substring(0, formatString.length-1);
$('#timeformat').html(formatString+" "+lds);
Here's an idea, that may or may not work.
Create a date where all the elements are distinct, like February 18th 1999 at 13:45, use toLocaleString(), then identify the elements based on their distinct values.
Could be kind of complicated and I don't have any code that might help with it, but it's an idea to be thrown out there, maybe you can make use of it.
EDIT: Here's some code:
var d = new Date(1999,1,18,13,45,0).toLocaleString();
document.write("<p>String: "+d+"</p>");
var f = d
.replace(/1999/,"%Y")
.replace(/99/,"%y")
.replace(/F[^ ]{3,}/i,"%M")
.replace(/F[^ ]+/i,"%m")
.replace(/PM/,"%A")
.replace(/pm/,"%a")
.replace(/18[^ ]+/,"%d%S") // day number with suffix
.replace(/18/,"%d")
.replace(/13/,"%H")
.replace(/1/,"%h")
.replace(/45/,"%i")
.replace(/00/,"%s");
// optionally add something to detect the day of the week (Thursday, here)
document.write("<p>Format: "+f+"</p>");
Output:
String: 18 February 1999 13:45:00
Format: %d %M %Y %H:%i:%s
Something like this ?
<script type="text/javascript">
var d=new Date();
document.write("Original form: ");
document.write(d + "<br />");
document.write("Formatted form: ");
document.write(d.toLocaleString());
//calculate change of the 2 dates
</script>

Categories

Resources