I have 2 questions about dates.
The first one is how can I get the "AM/PM" from a date in Javascript?
the second question is say I have this code
var convertedStartDate = new Date(dueDate);
var month = convertedStartDate.getMonth() + 1;
var day = convertedStartDate.getDate();
var year = convertedStartDate.getFullYear();
var shortDueDate = month + "/" + day + "/" + year;
Now as you can see I want always this format mm/dd/yyyy
So I am wondering if say dueDate is 1/9/2010 (mm/dd/yyyy) but the person entered it in as dd/mm/yyyy(some other format version of date).
would
month = 1
day = 9
year = 2010
Or do I have to tell it somehow to always convert into mm/dd/yyyy? Or does it do is own format so that it always would get the right order? Ie it does not matter what order they put the date in it would always get 9 as the day.
Here, give this a try:
now = new Date();
hour = now.getHours();
var tag = "";
if (hour >= 12) {
tag = "pm";
} else {
tag = "am";
}
As for the second part of your question, I'd just make those parts of the form separate fields, there really is no way otherwise. You're just going to have to write some hints into your form.
You need to always turn/convert whatever the user entered into a Javascript Date object. Remember - Javascript is local to the client's computer... a person in the USA will have different format settings than a person in the UK or China.
To keep things simple... suggest or present a hint near the input textbox the desired input format. Then, validate against that format using a Regex. This way you are almost guaranteed to get the desired date... well... unless the user has Javascript disabled. LOL... in that case... you need to convert on the server-side (you should always be doing this anyway).
To get the AM/PM of a time found some old code I wrote a long time ago. See the (remove am/pm) here you can replace it with a get using the substring.
function ValidateAdvancedTime(time, formatType){
time = time.replace(".", ":");
var newTime = time.substring(0, (time.indexOf(":") + 3)); // Strip out the seconds
var status = ValidateTime(newTime, formatType);
if(status == false)
return false;
var seconds = time.substring(time.indexOf(":") + 4, time.length);
if(seconds.length > 2)
**seconds = seconds.substring(0, 2); // Remove any AM/PM afterwards**
if(!isNaN(seconds)) { // Make sure its a number and it's between 0 and 59
if((seconds <= 59) && (seconds >= 0))
return true;
}
return false;
}
As far as the dates go I've never had any problems storing 1/9/2010 or 01/09/2010 in the database.
Related
I have a CloudCode function that is called from my iOS app. The function is supposed to create a "checkin" record and return a string to represent the last 30 days of check-ins and missed days.
The strange thing is that sometimes I get the expected results and sometimes I do not. It makes me think that there is some issue with the may I am using timezones - since that could result in a different set of "days in the past" depending on what time I run this function and what time of day I checked-in in the past. But I'm baffled and could use some help here.
It's also confusing me that I do not see all of my console.log() results appear in the parse log. Is that normal?? For example, in the for loop, I can uncomment the console.log entry and call the function but I will not see all of the days in the past listed - but they are included in the final array and text string.
Here is my complete function. Any help and suggestions are appreciated.
/* Function for recording a daily check in
*
* Calculates the number of days missed and updates the string used to display the check-in pattern.
* If no days missed then we increment the current count
*
* Input:
* "promiseId" : objectID,
* "timeZoneDifference" : String +07:00
*
* Output:
* JSON String eg. {"count":6,"string":"000000000000001111101010111111"}
*
*/
Parse.Cloud.define("dailyCheckIn", function(request, response) {
var promiseId = request.params.promiseId;
var timeZoneDifference = request.params.timeZoneDifference;
var currentUser = Parse.User.current();
if (currentUser === undefined) {
response.error("You must be logged in.");
}
if (timeZoneDifference === undefined || timeZoneDifference === "") {
//console.log("timeZoneDifference missing. Set to -07:00");
timeZoneDifference = '' + '-07:00'; // PacificTime as string
}
var moment = require('cloud/libs/moment.js');
// Query for the Promise
var Promise = Parse.Object.extend("Promise");
var queryforPromise = new Parse.Query(Promise);
queryforPromise.get(promiseId, {
success: function(promis) {
// Initialize
var dinarowString = "";
var dinarowCount = 0;
// Last Check In date from database (UTC)
var lastCheckInUTC = promis.get("lastCheckIn");
if (lastCheckInUTC === undefined) {
lastCheckInUTC = new Date(2015, 1, 1);
}
// Use moment() to convert lastCheckInUTC to local timezone
var lastCheckInLocalized = moment(lastCheckInUTC.toString()).utcOffset(timeZoneDifference);
//console.log('lastCheckIn: ' + lastCheckInUTC.toString());
//console.log('lastCheckInLocalized: ' + lastCheckInLocalized.format());
// Use moment() to get "now" in UTC timezone
var today = moment().utc(); // new Date();
//console.log('today: ' + today.format());
// Use moment() to get "now" in local timezone
var todayLocalized = today.utcOffset(timeZoneDifference);
//console.log('todayLocalized: ' + todayLocalized.format());
// 30 days in the past
var thirtydaysago = moment().utc().subtract(30, 'days');
//console.log("thirtydaysago = " + thirtydaysago.format());
// 30 days in the past in local timezone
var thirtydaysagoLocalized = thirtydaysago.utcOffset(timeZoneDifference);
//console.log('thirtydaysagoLocalized: ' + thirtydaysagoLocalized.format());
// Calculate the number of days since last time user checked in
var dayssincelastcheckin = todayLocalized.diff(lastCheckInLocalized, 'days');
//console.log("Last check-in was " + dayssincelastcheckin + " days ago");
// Function takes an array of Parse.Objects of type Checkin
// itterate over the array to get a an array of days in the past as numnber
// generate a string of 1 and 0 for the past 30 days where 1 is a day user checked in
function dinarowStringFromCheckins(checkins) {
var days_array = [];
var dinarowstring = "";
// Create an array entry for every day that we checked in (daysago)
for (var i = 0; i < checkins.length; i++) {
var checkinDaylocalized = moment(checkins[i].get("checkInDate")).utcOffset(timeZoneDifference);
var daysago = todayLocalized.diff(checkinDaylocalized, 'days');
// console.log("daysago = " + daysago);
days_array.push(daysago);
}
console.log("days_array = " + days_array);
// Build the string with 30 day of hits "1" and misses "0" with today on the right
for (var c = 29; c >= 0; c--) {
if (days_array.indexOf(c) != -1) {
//console.log("days ago (c) = " + c + "-> match found");
dinarowstring += "1";
} else {
dinarowstring += "0";
}
}
return dinarowstring;
}
// Define ACL for new Checkin object
var checkinACL = new Parse.ACL();
checkinACL.setPublicReadAccess(false);
checkinACL.setReadAccess(currentUser, true);
checkinACL.setWriteAccess(currentUser, true);
// Create a new entry in the Checkin table
var Checkin = Parse.Object.extend("Checkin");
var checkin = new Checkin();
checkin.set("User", currentUser);
checkin.set("refPromise", promis);
checkin.set("checkInDate", today.toDate());
checkin.setACL(checkinACL);
checkin.save().then(function() {
// Query Checkins
var Checkin = Parse.Object.extend("Checkin");
var queryforCheckin = new Parse.Query(Checkin);
queryforCheckin.equalTo("refPromise", promis);
queryforCheckin.greaterThanOrEqualTo("checkInDate", thirtydaysago.toDate());
queryforCheckin.descending("checkInDate");
queryforCheckin.find().then(function(results) {
var dinarowString = "000000000000000000000000000000";
var dinarowCount = 0;
if (results.length > 0) {
dinarowString = dinarowStringFromCheckins(results);
dinarowIndex = dinarowString.lastIndexOf("0");
if (dinarowIndex === -1) { // Checked in every day in the month!
// TODO
// If the user has checked in every day this month then we need to calculate the
// correct streak count in a different way
dinarowString = "111111111111111111111111111111";
dinarowCount = 999;
} else {
dinarowCount = 29 - dinarowIndex;
}
}
// Update the promise with new value and save
promis.set("dinarowString", dinarowString);
promis.set("dinarowCount", dinarowCount);
promis.set("lastCheckIn", today.toDate());
promis.save().then(function() {
response.success(JSON.stringify({
count: dinarowCount,
string: dinarowString
}));
});
}, function(reason) {
console.log("Checkin query unsuccessful:" + reason.code + " " + reason.message);
response.error("Something went wrong");
});
}); // save.then
},
error: function(object, error) {
console.error("dailyCheckIn failed: " + error);
response.error("Unable to check-in. Try again later.");
}
});
});
There's too much going on in your question to answer adequately, but I will be nice and at least point out a few errors that you should look into:
You take input in terms of a fixed offset, but then you are doing operations that subtract 30 days. It's entirely possible that you will cross a daylight saving time boundary, in which case the offset will have changed.
See "Time Zone != Offset" in the timezone tag wiki. In moment, you can use time zones names like "America/Los_Angeles" with the moment-timezone add-on.
From your example, I'm not even sure if time zone even matters or not for your use case.
You should not convert the Date to a string just to parse it again. Moment can accept a Date object, assuming the Date object was created correctly.
moment(lastCheckInUTC.toString()).utcOffset(timeZoneDifference)
becomes
moment(lastCheckInUTC).utcOffset(timeZoneDifference)
Since Date.toString() returns a locale-specific, implementation-specific format, you'll also see you have a warning in the debug console from moment.
As for the rest, we can't run your program and reproduce the results, so there's not much we can do to help. You need to start by debugging your own program, and then try to reproduce your error in a Minimal, Complete, and Verifiable example. Chances are, you'll solve your own problem along the way. If not, then you will have something in a better state to share with us.
I am answering my own question as I have found the solution.
I had two questions. The first was "why do I get unexpected (incorrect) results" and I suspected that it was related to the way I am using timezones. I would see different results from day to day depending on what time I check in.
The problem is actually related to the way that moment().diff() works. Diff does not calculate "days" the way I expected it to. If I compare 2am today with 11pm yesterday diff will say 0 days because it is less than 24 hours diff. If I compare 1am on Thursday with 8pm on the previous Monday, diff will report 2 days - not 3 as I expected. It's a precision issue. Diff thinks 2.4 days is 2 days ago. But it is more than 2 therefor it is 3 days ago.
We found that the easiest solution is to compare the two dates at midnight rather than at the actual time of day that is recorded in the database. This yields correct results for days. The rest of the code is working fine.
//Find start time of today's day
var todayLocalizedStart = todayLocalized.startOf('day');
for (var i = 0; i < checkins.length; i++) {
var checkinDaylocalized = moment(checkins[i].get("checkInDate")).utcOffset(timeZoneDifference);
//Find start time of checkIn day
var checkinDaylocalizedStart = checkinDaylocalized.startOf('day');
//Find number of days
var daysago = todayLocalizedStart.diff(checkinDaylocalizedStart, 'days');
// console.log("daysago = " + daysago);
days_array.push(daysago);
}
The second question I had was "is it normal to not see every console.log at runtime". I've talked with other Parse.com users and they report that Parse is inconsistent in logging. I was spending a lot of time debugging "problems" that were simply Parse not logging correctly.
Thanks to everyone that contributed to the answer.
I did make one other change - but it was not a bug. I replaced the query limit from 30 days in the past to simply "30". It's just a bit simpler with one less calculation.
I have got below java script code that will validates date range ... when the user entered the today date or any future dates I have set IsValid to true and then will do the save operation ....
for that purpose I have written below code ..
function Save(e) {
var popupNotification = $("#popupNotification").data("kendoNotification");
var container = e.container;
var model = e.model;
var isValid = true;
var compareDate = e.model.DeliveryDate;
alert(compareDate);
var todayDate = new Date();
var compareDateModified = new Date(compareDate)
alert(compareDateModified);
if (compareDateModified > todayDate || compareDateModified === todayDate) {
isValid = true;
}
else
isValid = false;
e.preventDefault();
if (isValid == false)
{
popupNotification.show("Delivery Date should be today date or Greater", "error");
}
$('#Previous').show();
$('#Next').show();
}
Its working fine when I give the future dates but its not working for today date. I also need to check the today's date. I am not able to figure it out the error alert when I try to enter to the today date .
You are comparing two objects of the same type, but different objects, so that will always result in 'unequal'
If you use date.getTime() you will get better results in your comparison - but only if the time component is the same of course.
Think of the Date object like a timestamp. It is based on the unix-style of timestamps (the amount of seconds since 1st January, 1970) so the Date object isn't the day, it is the Date AND the Time.
What you're comparing is the times as well, which could get a little iffy. If only days matter, try using:
fullCompareDate = compareDateModified.getFullYear() + "/" + compareDateModified.getMonth() + "/" + compareDateModified.getDate();
fullTodayDate= todayDate.getFullYear() + "/" + todayDate.getMonth() + "/" + todayDate.getDate();
if(compareDateModified>todayDate||fullCompareDate==fullTodayDate)
{
//Do something
}
This will compare the date and time to make sure they are greater OR check the current date with the compare date (as strings)
Another solution is to blank out the times on both dates:
compareDateModified.setHours(0,0,0,0);
todayDate.setHours(0,0,0,0);
if(compareDateModified>=todayDate)
{
//Do something
}
You are comparing the compareDateModified to todayDate on the millisecond level. To compare at the day level:
var todayDate = new Date();
todayDate.setHours(0,0,0,0);
//you may also have to truncate the compareDateModified to the first
//second of the day depending on how you setup compareDate
if (compareDateModified >= todayDate) {
isValid = true;
}
I have the following scenario that I am strugling to code.
I have a valuation date that is a string that is chosen by a user from a calander popup. What I need to do is take that date and pass it into a function that works outs a second date depending on the value of that date. If the first date is more than 7 days from the first day of the month use the first day of the month else use the last day of the month. This needs to happen in client side as this date need to be displayed after they have chosen the first date.
SO far I have the below:
Function CompareDate()
{ var date1 = document.getElementById("textbox1");
var x = new date();
var year = x.getYear();
var day = x.getDay();
var thisMonthFirstDay = new Date(year, month,1)
var thisMonthLastDate = ....
var 1day = 1000*60*60*24
var date1_ms = recdate
var date2ms = thisMonthFirstDay.gettime()
if(Math.round(difference_ms/1day) > 7
{var textbox = document,getelementbyid("textbox2");
textbox.value = texbox.value + thisMonthLastDate
}
else
{
textbox.value = texbox.value + thisMonthFirstDay }
}
Any examples of how this can be done would be greatly appeciated.
Cheers
getDate() will give you the day of month (e.g. 18), so if (getDate() <= 7) { outputDate = 1; } If you're having a problem getting the last day of each month for the else statement, I generally use a 12 capacity array with hard-coded values, adding 1 to February if (year % 4 == 0).
I have managed to resolve this after a finding the parseDate() function on a fiddler site. That allowed me to convert the date from this format (31 Jan 2013) to a date and then I could just use the getDay(function) to see if the day was > 7. From there it was easy!
Thanks for above suggestions.
This is for a system that essentially allows you to set the first date for a given event, then to set the recurrence period.
Eg. I set a date for a week from now, 19/07/2012, so I know that I have to put the cat out with the milk. I also set it to be a weekly notification, so in future weeks I want to be notified of the same.
That original date sits in my database, which is fine for week 1, but in week 2 I need to return the date as the original plus 1 week.
On the face of it, that may seem straightforward, but I need to make sure I can account for leap years and different recurrence frequencies (fortnightly, monthly, yearly, whatever).
I'd like to keep this as a javascript implementation - because it's quicker and I feel probably would require less code than updating dates in the database. Maybe it's not achievable, any pointers would be excellent.
I think these may be a starting point:
Given a start date , how to calculate number of years till current date in javascript
Given a date, how can I efficiently calculate the next date in a given sequence (weekly, monthly, annually)?
Update, I've written the below to return the amount of time to add in each different case, from there I can just use the answer below:
var strDate = $(this).find('.next').text();
var frequency = $(this).find('.occurs').text();
var frmDate = getDateObject(strDate);
var toDate = new Date();
var days = parseInt(Math.floor((frmDate - toDate) / 86400000));
if(days < 0) {
// find out how many WHOLE 'frequencies' have passed
var weeks = Math.ceil(0 - (days / 7));
var months = Math.ceil(0 - (monthDiff(toDate,frmDate)));
var years = Math.ceil(months / 12);
//alert(days + '/' + weeks + '/' + fortnights + '/' + months + '/' + quarters + '/' + years);
if(frequency == 'Weekly') { frmDate.add(weeks).weeks(); }
if(frequency == 'Fortnightly') { frmDate.add(weeks*2).weeks(); }
if(frequency == 'Monthly') { frmDate.add(months).months(); }
if(frequency == 'Quarterly') { frmDate.add(months*3).months(); }
if(frequency == 'Annually') { frmDate.add(years).years(); }
var newdate = frmDate.toString("dd/MM/yyyy");
//alert(newdate);
$(this).find('.next').text(newdate);
}
Also, the SQL implementation for this would be using DATEADD:
http://sql-plsql.blogspot.com/2010/07/dateadd.html
You don't have to worry about special dates like leap year and so forth, because most Date functions take care of that.
Alternatively, you can use the getDate(), getMonth() as the other user suggested.
var today = new Date();
today.setDate(today.getDate() + numberOfDaysToAdd);
What I would do (probably not the best solution, I'm just coming up with it right now) is to start from the initial date and use a loop: while the date you are observing is less than the current date, increment the observed date by a week (fortnight, month, year etc.). If you land on the current date, the event happens. Otherwise it's for another day.
You can use things like date.setDate(date.getDate()+1); to increment the date by a day, the same +7 for a week, using set/getMonth and set/getFullYear for months and years respectively. If you give a value out of bounds, JS will wrap it (so March 32nd becomes April 1st)
Please check out the following code for some raw idea
var someDate = new Date();
for(var i = 0 ; i < 7 ; i++)
{
someDate.setDate(someDate.getDate() + 1);
console.log(someDate)
}
You can test the same in the below fiddle
Consecutive 7 days from current day
i have 2 input fields for a check in date and a check out date. when the user puts in the dates it calculates the nights. However i dont want the user to be able to put a date 30 days after the check in date. Ive used an alert to bring up a message if nights is greater then 30 however the date u selected goes into the check out date. Im trying to use innerHTML to force the date in the check out to be what i want it to be ie 1 day after the check in date if they have selected more then 30 days. Heres part of my code.
function DoDepart() {
Date.fromUKFormat = function(sUK)
{
var A = sUK.split(/[\\\/]/);
A = [A[1],A[0],A[2]];
return new Date(Date.parse(A.join('/')));
}
var a = Date.fromUKFormat(document.getElementById('datepicker').value);
var b = Date.fromUKFormat(document.getElementById('departure').value);
var x = ((b - a) / (24*60*60*1000));
if (x > 30)
{
alert("check out date must be within 30 days of your check in date");
document.getElementById('departure').innerHTML = 'hey';<!--this bit must be wrong
}
document.getElementById('n').value = x;
};
any help would be appreciated
If #departure is a text input element, you should edit their value this way:
document.getElementById('departure').value= 'hey';