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

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>

Related

How to convert user timezone to UTC?

I'm using the TimeIt code on my site, it can be found here: http://codegen.in/timeit/
This is the direct link to the code: https://res.cloudinary.com/vsevolodts/raw/upload/v1503371762/timeit.min.js
It looks like this:
//version 3. 2017-08-13
function timeit() {
var next_run_array = []; //array of dates/time on a page used to rerun function if a change should happen during the session
var curDate = new Date();
Date.prototype.yyyymmdd = function() {
var mm = this.getMonth() + 1;
var dd = this.getDate();
return [this.getFullYear(),
(mm > 9 ? '' : '0') + mm,
(dd > 9 ? '' : '0') + dd
].join('-');
};
var curDateYMD = curDate.yyyymmdd();
$('.timeit').each(function() {
var end = $(this).data('end'),
start = $(this).data('start');
//check if date or time value has valid format and push it to the list of refresh anchors
var startDate = checkdate(start, this);
var endDate = checkdate(end, this);
nextrun(startDate);
nextrun(endDate);
//add a datetime when the page needs to be refreshed (now+24 hrs time span only)
function nextrun(date) {
var nextruntimeout = date - curDate;
if (nextruntimeout < 1000 * 60 * 60 * 24 && nextruntimeout > 1000) {
next_run_array.push(nextruntimeout);
}
}
// Main Function
//check if the evend outside of a desired time span
if (((startDate < endDate) && (startDate > curDate || endDate < curDate)) ||
((startDate > endDate) && (startDate >= curDate) && (endDate <= curDate))
) {
$(this).addClass('hidden');
} else {
$(this).removeClass('hidden');
}
//Support Functions
//correct data creation from a string. accepted format YYYY-MM-DD HH:MM
function parseISO8601(d) {
var isoExp = /^\s*(\d{4})-(\d\d)-(\d\d)?.(\d\d)?.(\d\d)\s*$/,
date = new Date(NaN),
datenew,
month,
dateString=d.substr(0, d.indexOf(' '));
parts = isoExp.exec(d);
if(parts) {
month = +parts[2];
date.setFullYear(parts[1], month - 1, parts[3]);
if(month != date.getMonth() + 1) {
date.setTime(NaN);
}
date = new Date(parts[1], month - 1, parts[3], parts[4], parts[5])
}
return date;
}
//unification of the date string to the format YYYY-MM-DD HH:MM
function checkdate(date, obj) {
if (date) {
//check if only time is set (HH:MM); if so, add today's date
if (String(date).length < 6 && String(date).indexOf(":") > -1) {
date = curDateYMD + ' ' + String(date);
}
//check if only date is set; if so add 00:00 to the end of date
if (String(date).indexOf(":") == -1) {
date = date + ' 00:00';
}
//check if date is valid (avoid valid time)
var res = date.split(":"),
h = String(res.slice(0, 1)),
hours = h.substr(h.length - 2),
minutes = res.slice(1);
var timetest = (hours < 24 && minutes < 60) ? true : false;
//check if date is could be created from a value; if fails try to parse a string to a format
var returndate = new Date(date);
if (returndate == 'Invalid Date') {
var returndate = parseISO8601(date);
};
if (returndate == 'Invalid Date' || !timetest) {
//highlight the element if the is an error. use own \.error class if needed
$(obj).addClass("error").attr('title', '"' + date + '" date is incorrect; please use YYYY-MM-DD HH:MM format');
}
return returndate.getTime();
} else {
//if datetime is not set, just return current date-time
return curDate.getTime();
}
}
});
/* Schedule next runs */
if (next_run_array.length > 0) {
var nextruntime = Math.min.apply(null, next_run_array);
console.log("next run of timeit function is in " + nextruntime / 1000 + "seconds");
setTimeout(function() {
timeit();
}, nextruntime);
}
}
timeit();
(
Then you just put the embed code:
<div class="timeit" data-start="2019-02-15" data-end="2019-07-25 23:59">
This content will be shown between 2019-02-15 - 2019-07-25
</div>...<script src="/js/timeit.js"></script>
The idea is: my content is being shown between a certain period of time. I would like it to work with the UTC time zone, but right now the code is getting the date/hour info from the user's local time zone. So my content becomes available for example not at 8 AM UTC, but at 8 AM of the user's local time zone. I would like to change that.
I really, really tried to work this out on my own, but I guess this is beyond my skill set (which is pretty low). I'm confused by all the info about those ISO 8601, new Date, Date, I can't really find where it says "get the time from this source" to replace it with "get it from UTC". So - if any of you would just take a look at it and tell me what to put where, I would be extremely grateful.
Thank you all for your time!
Since you can't use server-side scripting because of Weebly... You will have to rely on the client's clock which can be tweeked. And the hidden class can easily be removed... But it seems you don't have the choice.
Now, I will suggest you to forget about the TimeIT plugin.
When it comes to dates in JavaScript/jQuery, I always recommand the use of moment.js which is really easy to use (you won't have to perform complex caluculations anymore) and fully documented, so you can do whatever you wish.
Here, content hiding based on start/end dates in data attributes would look like this:
$(document).ready(function(){
var utc_date = moment().utc().format("YYYY-MM-DD HH:mm"); // Client's date/time in UTC
$(".timeit").each(function(){
var start = moment($(this).data("start")).format("YYYY-MM-DD HH:mm");
var end = moment($(this).data("end")).format("YYYY-MM-DD HH:mm");
console.log((utc_date>start && utc_date<end)?"Content displayed":"Content hidden");
$(this).addClass("hidden"); // Hide content by default
if(utc_date>start && utc_date<end){
$(this).removeClass("hidden"); // Show content if now is between start/end dates
}
});
}); // ready
.hidden{
display:none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
<div class="timeit" data-start="2019-02-15" data-end="2019-07-25 23:59">
This content will be shown between the dates in data attributes
</div>
You can try it in CodePen... Change the start date and hit "Run". I left some console logs so you can understand what is going on.
For more, explore moment.js documentation.

Interpret user entered dates in JavaScript

I was looking for a convenient method to take a date entered by a user and do the following:
1) Determine if the Date entered is valid, and if it is valid, return an object with:
2) A JavaScript Date object
3) The date formatted in mySQL format (YYYY-MM-DD)
4) The date formatted in typical format (MM-DD-YYYY)
In the end I wrote my own function that uses Regex and can handle an input of YYYY-MM-DD, YYYY/MM/DD, MM-DD-YY, MM/DD/YY, MM-DD-YYYY or MM/DD/YYYY.
The reason that the function returns mySQL format and regular format in the object is simply for convenience. My web app needs the typical format to display in the field and the mysQL format to send to the server when saving data.
The code is shown below in my answer. I'm sure there are ways to optimize the code, but I wrote it in parts for the ease of reading. And even if it was set to run every time a user entered data in a date field, it wouldn't bog anything down. Hopefully this helps someone!
UPDATE: momentjs is much better.
The code and an example can be seen here on this jsfiddle.
function interpretDate(stringDate){
var mysqlF = "(\\d{4})[-/](\\d{1,2})[-/](\\d{1,2})";
var dispF = "(\\d{1,2})[-/](\\d{1,2})[-/]((?:\\d{4})|(?:\\d{2}))";
var dispNoYearF = "(\\d{1,2})[-/](\\d{1,2})";
var dateFormats = "(^"+mysqlF+"$)|(^"+dispF+"$)|(^"+dispNoYearF+"$)";
//Let's try to extract the data
data = stringDate.match(dateFormats);
var month = -1;
var day = -1;
var year = -1;
//Check to see if the verification failed
if (data == undefined){
//Invalid date
return {valid: false, date: null, mysqlDate:null, displayDate: ""};
}
//Extract the data based on the entry type
if (data[1] != undefined){//YYYY-MM-DD
month = parseInt(data[3]);
day = parseInt(data[4]);
year = parseInt(data[2]);
}else if (data[5] != undefined){//MM-DD-YYYY or MM-DD-YY
month = parseInt(data[6]);
day = parseInt(data[7]);
year = parseInt(data[8]);
if (year < 100){
var yearString = new String(new Date().getFullYear());
year = parseInt(yearString.substr(0,2) + year);
}
}else if (data[9] != undefined){//MM-DD
month = parseInt(data[10]);
day = parseInt(data[11]);
year = parseInt(new Date().getFullYear());
}
//If we are here, we have three numbers, let's see if they make a real date
var extractedDate = new Date(year, month-1, day);
if (extractedDate.getFullYear() != year || extractedDate.getDate() != day || extractedDate.getMonth() != (month-1)){
return {valid: false, date: null, mysqlDate:null, displayDate: ""};
}
//We have a valid date, let's add front zeros
var monthFixed = month;
if (monthFixed < 10) monthFixed = "0"+monthFixed;
var dayFixed = day;
if (dayFixed < 10) dayFixed = "0"+dayFixed;
//We are done
return {valid: true, date: extractedDate, mysqlDate:year+"-"+monthFixed+"-"+dayFixed, displayDate: month+"/"+day+"/"+year};
}

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())

JavaScript Detecting Valid Dates

Possible Duplicate:
Detecting an “invalid date” Date instance in JavaScript
I was using the following to detect a valid date:
var text = $('#Date').val();
var date = Date.parse(text);
if (isNaN(date)) {
// Invalid date
}
But found that Date.parse thinks the following are valid dates (mm/dd/yyyy)
2/30/2011
11/31/2011
Any other way to detect invalid dates when the number of days surpasses the total number of
days in the month?
UPDATE: An even larger problem is that the jQuery validation plugin doesn't detect this as an invalid date either!
SOLUTION:
Based on #Guffa's comments I have created the following function to validate dates:
function validDate(text) {
var date = Date.parse(text);
if (isNaN(date)) {
return false;
}
var comp = text.split('/');
if (comp.length !== 3) {
return false;
}
var m = parseInt(comp[0], 10);
var d = parseInt(comp[1], 10);
var y = parseInt(comp[2], 10);
var date = new Date(y, m - 1, d);
return (date.getFullYear() == y && date.getMonth() + 1 == m && date.getDate() == d);
}
To check if a date is valid you can parse the components of the date, create a Date object from it, and check if the components in the data is the same as the parsed components. If you create a Date object from compnents that are out of range, the values will flow over to the next/previous period to create a valid date.
For example, new Date(2011,0,42) will create an object that contains the date 2/11/2011 instead of 1/42/2011.
By parsing the components instead of the full date you will also get around the problem with different date formats. My browser will for example expect a date format like y-m-d rather than d/m/y.
Example:
var text = '2/30/2011';
var comp = text.split('/');
var m = parseInt(comp[0], 10);
var d = parseInt(comp[1], 10);
var y = parseInt(comp[2], 10);
var date = new Date(y,m-1,d);
if (date.getFullYear() == y && date.getMonth() + 1 == m && date.getDate() == d) {
alert('Valid date');
} else {
alert('Invalid date');
}
Demo: http://jsfiddle.net/Guffa/UeQAK/
If your date format is fixed as M/D/YYYY, you could re-format the parsed date and see if it matches the input:
var d = new Date(Date.parse(str))
return str === (d.getMonth()+1)+'/'+d.getDate()+'/'+d.getYear();
However, that won't tolerate whitespace or zero-padded numbers.
If you don't need to keep the user's input exactly, you could just reformat the date anyway and pretend that was what they typed.
But if you can't do that either, I'd parse out the components myself using a RegExp and then compare them to values from the Date methods.
You could write a script to do this manually:
function checkDate(day, month) {
if ((month == 4 || month == 6 || month == 9 || month == 11) && day < 30) {
alert("Date is valid")
}
else if (month == 2 && day <= 28) {
alert("Date is valid")
}
else if ((month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) && day <= 31) {
alert("Date is valid")
}
else {
alert("Date is in-valid")
}
}
Of course, you would also need something to look out for leap years, but just remember that any year divisible by 4 and not by 100 is a leap year unless the first two digits of the year are divisible by 4. That should be easy to include in this function.
The example is wrong
the correct is
if ((month == 4 || month == 6 || month == 9 || month == 11) && day <= 30)
<= instead of =
But the example are great!
A simple, intrinsic way to achieve this can be:
let dateObj = document.getElementById('Date');
if (dateObj.validity.badInput) {
// show error message
}
Now some date formatting can be done, but HTML date-picker event has properties like badInput and valid to check invalid dates.

Strange Javascript Problem Involving split("/");

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?

Categories

Resources