How does this JavaScript statement calculate the date? - javascript

So I was looking at how I could display a Desktop Notification using a Google Chrome extensions when I came across these lines of code:
var time = /(..)(:..)/(Date()); // The prettyprinted time.
var hour = time[1] % 12 || 12; // The prettyprinted hour.
var period = time[1] < 12 ? 'a.m.' : 'p.m.'; // The period of the day.
What the heck does all of this do?

Fascinating, I've not seen this before:
/regex/(...);
EDIT: see this!
This:
/(..)(:..)/(Date());
// seems to emulate the functionality of exec()
Will return the match (array of matched groups) of the regular expression, /(..)(:..)/, against the string (Date()):
"Thu Jul 08 2010 09:40:38 GMT+0200 (W. Europe Daylight Time)"
(or whatever time it happens to be)
The returned array (the match), in this case, is:
["09:40", "09", ":40"]
This line:
var hour = time[1] % 12 || 12;
...simply determines the hour. If the hour is falsey (i.e. 0) then it defaults to 12 -- this makes it possible for the next statement to return the correct am/pm suffix. (12:00 is am).

The first line is using a regular expression to extract the time element from the string returned by Date(). For instance, this might be '08:37' The brackets in this regular expression give two different 'groups' of characters, the first group matching '08', the second matching '37'
The second line is taking the first set of characters, which will be automatically converted to a number, and getting the remainder of division by 12. Presumably to turn a 24 hour clock number into a 12 hour clock number. '|| 12' acts to return 12 just in case the remainder is 0.
The third line uses a ternary conditional operator to add 'a.m' just in case the hour is smaller than 12, otherwise 'p.m.'

Related

Deterministic length of JS new Date().getTime() string in the modern era: Unix Epoch Time

console.log(new Date().getTime());
I have a silly question: In the modern era, is the length of JS new Date().getTime() always 13? Both JS and Java give time strings of this length.
My issue is that I have a random JS string created with
function generateUniqueID() {
return new Date().getTime() + '' + Math.round(Math.random() * Math.pow(10,6));
}
This string concatenates a Time string with a random number. I need to compare 2 IDs to see which one is for an earlier Date. But the random part of this string isn't always a 6-digit number, so I can't truncate the trailing 6 digits and consider that the time string. To get the time string, I can consider the first 13 digits. That seems to be the Unix Epoch Time string in the modern era.
But is that reliable? When would getTime() start giving 14 digits?
Also, if I look up Unix Epoch Time on Wikipedia, I see a 10-digit number as the current Unix Time, not 13-digit: 1637093681.
https://en.wikipedia.org/wiki/Unix_time
Updated
I see the length changes at this point: 2281-11-20 and 2281-11-21
console.log(new Date('2286-11-20').getTime().toString().length);
console.log(new Date('2286-11-21').getTime().toString().length);
The timestamp is milliseconds since 1970-01-01 00:00:00 UTC (the same as the Unix epoch). Subtract the current timestamp from 10000000000000 to get the number of milliseconds until it overflows to 14 digits, which is 8,362,906,319,000. Then divide this by the number of milliseconds in a year, which is about 31,557,600,000, to get the number of years until it reaches that value.
This is about 265 years.

JavaScript regexp parse date/time to milliseconds

I need a little bit of help with a regular expression to convert a date into milliseconds using regular expressions.
I am not sure what regular expression I need to do this.
Here are a few example dates:
3 dagar, 12:00:46
2 dagar, 8:01:00
1 dag, 11:34:00
0 dagar, 0:04:00
Again, I'd like a regexp that will parse these dates into milliseconds.
Alternatively I could use a library like this, to parse the date. But I have not much experience with that either.
The following regex captures days, hours, minutes and seconds.
I asume that you want the number of milliseconds since 1 Jan 1970 (epoch).
We initialize a Date object with the captured info and extract the milliseconds:
var regexp = /([0-9]*) [a-z]*, ([0-9]*):([0-9]*):([0-9]*)/;
var match = regexp.exec('3 dagar, 12:00:46'); //insert your timespan as text here
var date = new Date(1970, 0, parseInt(match[1]) + 1, match[2], match[3], match[4]);
// var result = Math.floor(date.getTime()/1000); //seconds
var result = date.getTime() - date.getTimezoneOffset() * 60000; //milliseconds
We also need to consider the timezone. The date.getTimezoneOffset() returns the offset in minutes.
Maybe you want to test this in rubular and adjust because it may cause problems if the input does not comply with the format that you provided.

Check valid date combinations using Regex?

A user can enter a few valid date combinations into an input :
Examples : ( all combinations are allowed 3!=6)
feb 7 2012
feb 07 2012
7 feb 2012
2012 7 feb
...
All are valid dates.
I have also managed to create a regex which check it :
/^(?=.*\b(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)\b)(?=.*(\b[1‌2]\d{3}\b))(?=.*\b(0[1-9]|[12]\d|3[01])\b).*$/i
Which means :
(?=.*\b(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)\b) : I'm expecting one of those values at the future.
(?=.*(\b[1‌2]\d{3}\b)) : I'm expecting year : 1xxx or 2xxx
(?=.*\b(0[1-9]|[12]\d|3[01])\b) I'm expecting day : 0x or 1x or 2x or 3x
All are OK.
So where is the problem ?
My regex also matches an invalid solutions which includes a valid solution :
IE : feb 13 2012 4 will also pass.
Console :
/^(?=.*\b(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)\b)(?=.*(\b[1‌2]\d{3}\b))(?=.*\b(0[1-9]|[12]\d|3[01])\b).*$/i.test('feb 13 2012 4') //true
Question :
How can I enhance my regex in order to find a strict match ?
p.s.
Checking new Date(xxx) is also a solution , but I'm looking for regex solution.(to improve my regex skills).
Write a regexp for each format:
RE1 - recognizes MON DD YYYY = (?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)\s+(?:0?[1-9]|[12]\d|3[01])\s+[12]\d{3}
RE2 - recognizes DD MON YYYY = (?:0?[1-9]|[12]\d|3[01])\s+(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)\s+[12]\d{3}
RE3 - recognizes YYYY DD MON = [12]\d{3}\s+(?:0?[1-9]|[12]\d|3[01])\s+(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)
Then combine them:
/^(?:RE1|RE2|RE3)$/i
Create one look-forward (?=...) group at the beginning, then optional groups for digits before or after the month block. The regex below works for all of your examples (see the unit tests at the linked page). Edit: it now matches all 3!=6 allowed combinations, but no impermissible combinations like 2 feb 1978 4.
/^(?=[a-z]{3}\s(\d{1,2}\s\d{4}|\d{4}\s\d{1,2})$|\d{1,2}\s[a-z]{3}\s\d{4}$|\d{4}\s[a-z]{3}\s\d{1,2}$|(\d{1,2}\s\d{4}|\d{4}\s\d{1,2})\s[a-z]{3}$)([12]\d{3}\s|\d{1,2}\s){0,2}(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)(\s\d{1,2}|\s[12]\d{3}){0,2}$/i
Debuggex Demo
Explanation:
The entire expression must look like one of the following:
Three of [a-z] followed by a day, then a year
Three of [a-z] followed by a year, then a day
A day, three of [a-z], and a year
A year, three of [a-z], and a day
A day, a year, then three of [a-z]
A year, a day, then three of [a-z]
Optionally match one or both of the number groups
Match the three-letter month code
Optionally match one or both of the number groups

JavaScript incorrectly converting milliseconds to date?

I've noticed an issue with some data I'm processing (2000+ lines of data).
The problem is very strange: the code works fine! UNTIL a specific date is reached (in this case 01/08/2011) when JavaScript fails to generate the correct date?
So, to explain: I'm taking a string in the format of 'dd/mm/yyyy' and doing (which doesn't work):
var date = '01/08/2011'.split('/');
var milliseconds = new Date(date[2], parseInt(date[1]) - 1, date[0]).getTime(); => 1291161600000
new Date(1291161600000); => Wed Dec 01 2010 00:00:00 GMT+0000 (GMT)
...but yet that exact code works fine with any date before the 1st August 2011?
So try again with 29/07/2011...
var date = '29/07/2011'.split('/');
var milliseconds = new Date(date[2], parseInt(date[1]) - 1, date[0]).getTime(); => 1311894000000
new Date(1311894000000); => Fri Jul 29 2011 00:00:00 GMT+0100 (BST)
The only difference is the (GMT) and (BST) values returned, which suggests a locale issue. But why would that occur, and how can I fix the code to work around that?
Many thanks for any help you can give me.
You are doing octal!
Use a radix!
parseInt(date[1],10)
From the MDN Docs parseInt(string[, radix]):
If radix is undefined or 0, JavaScript assumes the following:
If the input string begins with "0x" or "0X", radix is 16 (hexadecimal).
If the input string begins with "0", radix is eight (octal). This feature is non-standard, and some implementations deliberately do not
support it (instead using the radix 10). For this reason always
specify a radix when using parseInt.
If the input string begins with any other value, the radix is 10 (decimal).

Regular Expression | Leap Years and More

I've recently been looking for a regular expression to do some client side date checking, and I haven't been able to find one that can satisfy the following criteria:
Has a range from 1800 - Now
Performs proper date checking with leap years
MM/DD/YYYY Form
Invalid Date Checking
(These constraints were outside of my scope and are a requirement as per the client, despite my efforts to convince them this wasn't the best route)
Current code:
$('input').keyup(function()
{
var regex = /^(?:(0[1-9]|1[012])[\/.](0[1-9]|[12][0-9]|3[01])[\/.](18|19|20)[0-9]{2})$/;
$(this).toggleClass('invalid',!regex.test($(this).val()));
});
Update:
I should note that this is primarily to see if a regular expression like this would be possible (as the use of a Regex is not my choice in this matter). I am aware of the other (and better) options for validating a date, however as previously mentioned - this is to see if it was possible through a regular expression.
As is mentioned elsewhere, regular expressions almost certanily not what you want. But, having said that, if you really want a regular expression, here is how it is built:
31 day months
(0[13578]|1[02])[\/.](0[1-9]|[12][0-9]|3[01])[\/.](18|19|20)[0-9]{2}
30 day months
(0[469]|11)[\/.](0[1-9]|[12][0-9]|30)[\/.](18|19|20)[0-9]{2}
February 1-28 always valid
(02)[\/.](0[1-9]|1[0-9]|2[0-8])[\/.](18|19|20)[0-9]{2}
February 29 also valid on leap years
(02)[\/.]29[\/.](((18|19|20)(04|08|[2468][048]|[13579][26]))|2000)
which means it would be this if you put it all together:
((0[13578]|1[02])[\/.](0[1-9]|[12][0-9]|3[01])[\/.](18|19|20)[0-9]{2})|((0[469]|11)[\/.](0[1-9]|[12][0-9]|30)[\/.](18|19|20)[0-9]{2})|((02)[\/.](0[1-9]|1[0-9]|2[0-8])[\/.](18|19|20)[0-9]{2})|((02)[\/.]29[\/.](((18|19|20)(04|08|[2468][048]|[13579][26]))|2000))
This version is a little shorter, but a little harder to understand.
((0[13578]|1[02])[\/.]31[\/.](18|19|20)[0-9]{2})|((01|0[3-9]|1[1-2])[\/.](29|30)[\/.](18|19|20)[0-9]{2})|((0[1-9]|1[0-2])[\/.](0[1-9]|1[0-9]|2[0-8])[\/.](18|19|20)[0-9]{2})|((02)[\/.]29[\/.](((18|19|20)(04|08|[2468][048]|[13579][26]))|2000))
These scripts are long and unmaintainable. It should be clear that this isn't a good idea, but it is possible.
Caveats:
range 1800-2099 (more can be added without too much difficulty, but requires changes in 4-6 disparate places)
requires 2 digit months and days (the strictness could be removed from the expression in ~8 places)
[\/.] as seperators (8 places)
Hasn't been tested (we could check it against all digit combinations and compare with the javascript date function? [proof that we're reinventing the wheel])
I would suggest that you abandon the attempt to use regular expressions for this. You're much better off parsing the date into its constituent parts (month, day, year), and then using numerical comparisons to make sure it's in the proper range.
Better yet, see if the Javascript Date.parse function will do what you want.
Parsing dates with regular expressions is possible, but frustrating. It's hard to get right, the expression is difficult for non-regex wizards to understand (which means it's difficult to prove that the thing is correct), and it is slow compared to other options.
This is how I would do it:
function validate( input ) {
var date = new Date( input );
input = input.split( '/' );
return date.getMonth() + 1 === +input[0] &&
date.getDate() === +input[1] &&
date.getFullYear() === +input[2];
}
Usage:
validate( '2/1/1983' ) // true
validate( '2/29/1983' ) // false
validate( '2/29/1984' ) // true (1984 is a leap year)
Live demo: http://jsfiddle.net/9QNRx/
this regular expression for YYYY-MM-DD format
((18|19|20)[0-9]{2}[\-.](0[13578]|1[02])[\-.](0[1-9]|[12][0-9]|3[01]))|(18|19|20)[0-9]{2}[\-.](0[469]|11)[\-.](0[1-9]|[12][0-9]|30)|(18|19|20)[0-9]{2}[\-.](02)[\-.](0[1-9]|1[0-9]|2[0-8])|(((18|19|20)(04|08|[2468][048]|[13579][26]))|2000)[\-.](02)[\-.]29
Obviously regular expressions are not the ideal way to do this. Also, it's much safer to be working with YYYY-MM-DD (ISO 8601) format, not MM/DD/YYYY.
That said, here's going for the shortest fully-working regular expression for dates from 01/01/1800 to 12/31/2099:
^(((0[1-9]|1[012])\/(?!00|29)([012]\d)|(0[13-9]|1[012])\/(29|30)|(0[13578]|1[02])\/31)\/(18|19|20)\d{2}|02\/29\/((18|19|20)(0[48]|[2468][048]|[13579][26])|2000))$
Length: 162 characters.
Breakdown:
^ # start
(
( # non-leap months & days
(0[1-9]|1[012])/(?!00|29)([012]\\d) # all months, days 01-28, uses negative lookahead
|
(0[13-9]|1[012])/(29|30) # all months except feb, days 29,30
|
(0[13578]|1[02])/31 # all 31 day months, day 31 only
)
/
(18|19|20)\\d{2} # all years
|
02/29 # leap day
/
(
(18|19|20)(0[48]|[2468][048]|[13579][26]) # leap years not divisible by 100
|
2000 # leap years divisible by 100
)
)
$ # end
Here's a fiddle that tests all use cases from 00/00/1800 to 99/99/2099.
Also, for more fun, here's another fiddle that generates the lousiest possible regular expression that still works, 1205306 characters long. It looks something like this:
^(01/01/1800|01/02/1800|01/03/1800|...|12/29/2099|12/30/2099|12/31/2099)$
RegEx to check for valid dates following ISO 8601, SQL standard.
Has a range from 1000-9999
Checks for Invalid Dates
Checks for valid leap year dates
Format: YYYY-MM-DD HH:MM:SS
^([1-9]\d{3}[\-.](0[13578]|1[02])[\-.](0[1-9]|[12][0-9]|3[01]) ([01]\d|2[0123]):([012345]\d):([012345]\d))|([1-9]\d{3}[\-.](0[469]|11)[\-.](0[1-9]|[12][0-9]|30) ([01]\d|2[0123]):([012345]\d):([012345]\d))|([1-9]\d{3}[\-.](02)[\-.](0[1-9]|1[0-9]|2[0-8]) ([01]\d|2[0123]):([012345]\d):([012345]\d))|(((([1-9]\d)(0[48]|[2468][048]|[13579][26])|(([2468][048]|[13579][26])00)))[\-.](02)[\-.]29 ([01]\d|2[0123]):([012345]\d):([012345]\d))$
^(((?:(?:1[6-9]|[2-9]\d)?\d{2})(-)(?:(?:(?:0?[13578]|1[02])(-)31)|(?:(?:0?[1,3-9]|1[0-2])(-)(?:29|30))))|(((?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))(-)(?:0?2(-)29))|((?:(?:(?:1[6-9]|[2-9]\d)?\d{2})(-)(?:(?:0?[1-9])|(?:1[0-2]))(-)(?:0[1-9]|1\d|2[0-8]))))$
Please try the above Reg Expression. I tried multiple combinations and found to be working.
Please check if this works for you too.
Format Accepted : YYYY-MM-DD
Year accepted from 1600
This is the RegEx I use for date validation on client-side. It has a range from 1000 to 2999, validates leap years and optionally the time part. Isn't it gorgeous :)
var r = /^(0[1-9]|1\d|2[0-8]|29(?=-\d\d-(?!1[01345789]00|2[1235679]00)\d\d(?:[02468][048]|[13579][26]))|30(?!-02)|31(?=-0[13578]|-1[02]))-(0[1-9]|1[0-2])-([12]\d{3})(\s([01]\d|2[0-3]):([0-5]\d):([0-5]\d))?$/gm;
r.test('20-02-2013 10:01:07'); // true
r.test('29-02-1700'); // false
r.test('29-02-1604 14:01:45'); // true
r.test('29-02-1900 20:10:50'); // false
r.test('31-12-2000'); // true
r.test('31-11-2008 05:05:05'); // false
r.test('29-02-2004 05:01:23'); // true
r.test('24-06-2014 24:10:05'); // false
I was trying to validate YYYY-MM-DD, where YYYY can be two digit and MM and DD can be one. This is what I came up with. It treats all centuries as leap years.
((\d\d)?\d\d-((0?(1|3|5|7|8)|10|12)-(31|30|[21]\d|0?[1-9])|(0?(4|6|9)|11)-(31|30|[21]\d|0?[1-9])|0?2-((2[0-8]|1\d)|0?[1-9]))|(\d\d)?((0|2|4|6|8)(0|4|8)|(1|3|5|7|9)(2|6))-0?2-29)
Adding my answer just for sport - otherwise I fully agree with #Jim.
This will match leap years, including the ones with digits fewer or more than 4.
^\d*((((^|0|[2468])[048])|[13579][26])00$)|((0[48]|(^0*|[2468])[048]|[13579][26]))$
A mini test case in Ruby (^ replaced with \A and $ with \Z, because Ruby):
r = /\A\d*((((\A|0|[2468])[048])|[13579][26])00\Z)|((0[48]|(\A0*|[2468])[048]|[13579][26]))\Z/
100000.times do |year|
leap = year % 4 == 0 && ((year % 100 != 0) || (year % 400 == 0))
leap_regex = !year.to_s[r].nil?
if leap != leap_regex
print 'Assertion broken:', year, leap, leap_regex, "\n"
end
end
Using moment (not regex) I've done the following:
Assuming you have an ISO date as a string value:
var isoDate = '2016-11-10';
var parsedIsoDate = moment(isoDate, ['YYYY-MM-DD'], true).format('YYYY-MM-DD');
if (parsedIsoDate !== isoDate) {
// Invalid date.
}
Hello Find RegEx for your Requirement
Has a range from 1800
Now Performs proper date checking with leap years
DD/MM/YYYY Format
Invalid Date Checking
^(?:(?:31(/)(?:0[13578]|1[02]))\1|(?:(?:29|30)(/)(?:0[13-9]|1[0-2])\2))(?:(?:18|19|20)\d{2})$|^(?:29(/)02\3(?:(?:(?:(?:18|19|20))(?:0[48]|[2468][048]|[13579][26]))))$|^(?:0?[1-9]|1\d|2[0-8])(/)(?:(?:0[1-9])|(?:1[0-2]))\4(?:(?:18|19|20)\d{2})$
Image and debug RegEx At https://www.debuggex.com/
Testing:
DD/MM/YYYY
01/12/190 Not Match
29/02/1903 Not Match
37/02/1903 Not Match
09/03/1703 Not Match
09/03/2103 Not Match
09/31/2103 Not Match
29/02/1904 - Match
01/12/1988 - Match
((0[13578]|1[02])[/.]31/.[0-9]{2})|((01|0[3-9]|1[1-2])/./.[0-9]{2})|((0[1-9]|1[0-2])/./.[0-9]{2})|((02)[/.]29/.)
The short version answer does not work for 10/29 and 10/30 any year the long version does work below is a simple java script program I wrote to test
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.joda.time.LocalDate;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
public class RegxDateTest {
public static void main(String[] args) {
// String to be scanned to find the pattern.
String line = "This order was placed for QT3000! OK?";
String pattern ="((0[13578]|1[02])[\\/.]31[\\/.](18|19|20)[0-9]{2})|((01|0[3-9]|1[1-2])[\\/.](29|30)[\\/.](18|19|20)[0-9]{2})|((0[1-9]|1[0-2])[\\/.](0[1-9]|1[0-9]|2[0-8])[\\/.](18|19|20)[0-9]{2})|((02)[\\/.]29[\\/.](((18|19|20)(04|08|[2468][048]|[13579][26]))|2000))";
// Create a Pattern object
Pattern r = Pattern.compile(pattern);
LocalDate startDate = new LocalDate("1950-01-01");
LocalDate endDate = new LocalDate("2020-01-01");
for (LocalDate date = startDate; date.isBefore(endDate); date = date.plusDays(1))
{
if (date.toString("MM/dd/yyyy").matches(pattern)) {
// System.out.println("This date does match: " + date.toString("MM/dd/yyyy") );
}else{
System.out.println("This date does not match: " + date.toString("MM/dd/yyyy") );
}
}
String baddate1="02/29/2016";
if (baddate1.matches(pattern)) {
System.out.println("This date does match: " + baddate1 );
}else{
System.out.println("This date does not match: " + baddate1 );
}
System.out.println("alldone: " );
}
}

Categories