Get date from period number in Actionscript - actionscript-3

I have a table which containt a date, a number for the number of weeks per period, and a year. the user then enters a date and I can calculate the period number from this. But I'd like to do it the other way too: Entering a period number and get the start and end date of the period from this. Unfortunately, I can't seem to get the right logic. Could anyone guide me with this?
Thank you.
EDIT:
options[0] being the start date from the database and options[1] the number of weeks for one period.
This is the function I already have and which works:
private function dateToPeriod(date:Date):Number
{
var d = new Date(options[0]);
var periode = Math.floor((date.time - d.time)/(604800000*options[1])+1);
return periode;
}
let's say my start date it 12/12/2009, then passing 12/12/2009 to this function would return 1 since it's the first "period" from this date (in week number).
What I want is to make a periodToDate function.

EDITED ANSWER BASED ON NEW INFO
Alright, this is pretty simple then. You can add values onto the date property. Try this, again, not tested.
public function addPeriodToDate(date:Date, period:int, numWeeksInPeriod:int):Date
{
var periodDate:Date = new Date(date.time);
periodDate.date += period * numWeeksInPeriod;
return periodDate;
}
END EDIT
I haven't tested this, just some quick code, but I think this should get you going in the right direction.
private function dateToPeriod(date:Date):Number
{
var d = new Date(options[0]);
var diffInMilliseconds:Number = date.time - d.time;
var diffInWeeks:Number = diffInMilliseconds / 1000 / 60 / 60 / 24 / 7;
var weeksInPeriod:Number = options[1];
var period:int = diffInWeeks / weeksInPeriod + 1;
return period;
}

Related

Google Script Forcing Date Format [duplicate]

I'm trying to get from a time formatted Cell (hh:mm:ss) the hour value, the values can be bigger 24:00:00 for example 20000:00:00 should give 20000:
Table:
if your read the Value of E1:
var total = sheet.getRange("E1").getValue();
Logger.log(total);
The result is:
Sat Apr 12 07:09:21 GMT+00:09 1902
Now I've tried to convert it to a Date object and get the Unix time stamp of it:
var date = new Date(total);
var milsec = date.getTime();
Logger.log(Utilities.formatString("%11.6f",milsec));
var hours = milsec / 1000 / 60 / 60;
Logger.log(hours)
1374127872020.000000
381702.1866722222
The question is how to get the correct value of 20000 ?
Expanding on what Serge did, I wrote some functions that should be a bit easier to read and take into account timezone differences between the spreadsheet and the script.
function getValueAsSeconds(range) {
var value = range.getValue();
// Get the date value in the spreadsheet's timezone.
var spreadsheetTimezone = range.getSheet().getParent().getSpreadsheetTimeZone();
var dateString = Utilities.formatDate(value, spreadsheetTimezone,
'EEE, d MMM yyyy HH:mm:ss');
var date = new Date(dateString);
// Initialize the date of the epoch.
var epoch = new Date('Dec 30, 1899 00:00:00');
// Calculate the number of milliseconds between the epoch and the value.
var diff = date.getTime() - epoch.getTime();
// Convert the milliseconds to seconds and return.
return Math.round(diff / 1000);
}
function getValueAsMinutes(range) {
return getValueAsSeconds(range) / 60;
}
function getValueAsHours(range) {
return getValueAsMinutes(range) / 60;
}
You can use these functions like so:
var range = SpreadsheetApp.getActiveSheet().getRange('A1');
Logger.log(getValueAsHours(range));
Needless to say, this is a lot of work to get the number of hours from a range. Please star Issue 402 which is a feature request to have the ability to get the literal string value from a cell.
There are two new functions getDisplayValue() and getDisplayValues() that returns the datetime or anything exactly the way it looks to you on a Spreadsheet. Check out the documentation here
The value you see (Sat Apr 12 07:09:21 GMT+00:09 1902) is the equivalent date in Javascript standard time that is 20000 hours later than ref date.
you should simply remove the spreadsheet reference value from your result to get what you want.
This code does the trick :
function getHours(){
var sh = SpreadsheetApp.getActiveSpreadsheet();
var cellValue = sh.getRange('E1').getValue();
var eqDate = new Date(cellValue);// this is the date object corresponding to your cell value in JS standard
Logger.log('Cell Date in JS format '+eqDate)
Logger.log('ref date in JS '+new Date(0,0,0,0,0,0));
var testOnZero = eqDate.getTime();Logger.log('Use this with a cell value = 0 to check the value to use in the next line of code '+testOnZero);
var hours = (eqDate.getTime()+ 2.2091616E12 )/3600000 ; // getTime retrieves the value in milliseconds, 2.2091616E12 is the difference between javascript ref and spreadsheet ref.
Logger.log('Value in hours with offset correction : '+hours); // show result in hours (obtained by dividing by 3600000)
}
note : this code gets only hours , if your going to have minutes and/or seconds then it should be developped to handle that too... let us know if you need it.
EDIT : a word of explanation...
Spreadsheets use a reference date of 12/30/1899 while Javascript is using 01/01/1970, that means there is a difference of 25568 days between both references. All this assuming we use the same time zone in both systems. When we convert a date value in a spreadsheet to a javascript date object the GAS engine automatically adds the difference to keep consistency between dates.
In this case we don't want to know the real date of something but rather an absolute hours value, ie a "duration", so we need to remove the 25568 day offset. This is done using the getTime() method that returns milliseconds counted from the JS reference date, the only thing we have to know is the value in milliseconds of the spreadsheet reference date and substract this value from the actual date object. Then a bit of maths to get hours instead of milliseconds and we're done.
I know this seems a bit complicated and I'm not sure my attempt to explain will really clarify the question but it's always worth trying isn't it ?
Anyway the result is what we needed as long as (as stated in the comments) one adjust the offset value according to the time zone settings of the spreadsheet. It would of course be possible to let the script handle that automatically but it would have make the script more complex, not sure it's really necessary.
For simple spreadsheets you may be able to change your spreadsheet timezone to GMT without daylight saving and use this short conversion function:
function durationToSeconds(value) {
var timezoneName = SpreadsheetApp.getActive().getSpreadsheetTimeZone();
if (timezoneName != "Etc/GMT") {
throw new Error("Timezone must be GMT to handle time durations, found " + timezoneName);
}
return (Number(value) + 2209161600000) / 1000;
}
Eric Koleda's answer is in many ways more general. I wrote this while trying to understand how it handles the corner cases with the spreadsheet timezone, browser timezone and the timezone changes in 1900 in Alaska and Stockholm.
Make a cell somewhere with a duration value of "00:00:00". This cell will be used as a reference. Could be a hidden cell, or a cell in a different sheet with config values. E.g. as below:
then write a function with two parameters - 1) value you want to process, and 2) reference value of "00:00:00". E.g.:
function gethours(val, ref) {
let dv = new Date(val)
let dr = new Date(ref)
return (dv.getTime() - dr.getTime())/(1000*60*60)
}
Since whatever Sheets are doing with the Duration type is exactly the same for both, we can now convert them to Dates and subtract, which gives correct value. In the code example above I used .getTime() which gives number of milliseconds since Jan 1, 1970, ... .
If we tried to compute what is exactly happening to the value, and make corrections, code gets too complicated.
One caveat: if the number of hours is very large say 200,000:00:00 there is substantial fractional value showing up since days/years are not exactly 24hrs/365days (? speculating here). Specifically, 200000:00:00 gives 200,000.16 as a result.

Actionscript 3 : get time to specific timezone (not the computer one)

I have an UTC timestamp and I would like to display the corresponding date and hour in a specific timezone (e.g. France local time) which is not the local timezone of the computer which might be in US. It seems complicated to take into account Daylight saving time.
On Flash/as3 documentation, I only found the Date class which have no function to specify the timezone (only use local time or UTC).
If I understand your problem, flash.globalization.DateTimeFormatter is your solution.
The DateTimeFormatter class provides locale-sensitive formatting for
Date objects and access to localized date field names. The methods of
this class use functions and settings provided by the operating
system.
Here's a function i found somewhere, probably right on stack oveflow to check if daylight savings is in effect.
public static function isObservingDTS(): Boolean {
var winter: Date = new Date(2011, 01, 01); // after daylight savings time ends
var summer: Date = new Date(2011, 07, 01); // during daylight savings time
var now: Date = new Date();
var winterOffset: Number = winter.getTimezoneOffset();
var summerOffset: Number = summer.getTimezoneOffset();
var nowOffset: Number = now.getTimezoneOffset();
if ((nowOffset == summerOffset) && (nowOffset != winterOffset)) {
return true;
} else {
return false;
}
}
flex will keep a date in UTC and a timezone offset. any displaying of the date will show the timezone corrected form of the date, unless you calculate the new time and spit the date out as a string. something like this
private function convertToTimezone(dtDate: Date, timezoneOffset: Number = 0): String {
//timezoneOffset in minutes
dtDate.setTime(dtDate.getTime() + (timezoneOffset * 60000) + (isObservingDTS() ? (60 * 60 * 1000) : 0));
return dtDate.toUTCString();
}
not very elegant, but it should get you there.

Calculate time range and parse date

I have simple spreadsheet and need to calculate time ranges, according to the image below:
My rule is basically a simple math operation: (end date - initial date) - "09:00:00".
My result column gives me something like: -0:21:00 and it's correct.
I have my columns formatted as "hour" (Format > Number > Hours). I need to get the sum up of third column and send the result through e-mail. Part of the code was intentionally omitted. Below my script snippet:
var data = dataRange.getValues();
for (i in data) {
var row = data[i];
var to = row[0]; // e-mail
var total = row[1]; // total column
msg = "Total hours: " + Utilities.formatDate(total, "GMT-0300", "HH:mm:ss");
subject = "Test";
MailApp.sendEmail(to, subject, msg);
}
When I try to format Utilities.formatDate(...) before sending e-mail, the hour goes wrong. I've tried to remove Utilities call, passing the hour directly, but it gives me the following result:
Fri Dec 29 1899 23:45:28 GMT-0300 (BRT)
I realized where is my total var must be a JavaScript Date object, but it didn't work also. I need that my result column were send by e-mail.
I would dissociate the presentation in the spreadsheet from what you need to send in the email.
The result you get that in your column is displayed correctly, but represents the offset in milliseconds (displayed in hours) from the 1st January 1900 at 00:00:00 GMT.
So when you convert that to a date that is what you get.
Instead, that the number of milliseconds between the two dates and use a function that will return a 'human readable' number ... such as the one described here:
Convert time interval given in seconds into more human readable form
Good Luck
Solved my problem with a simple approach and Math.round(...) makes it quite acceptable:
function getReadableTime(ms) {
var spreadsheetTimezone = SpreadsheetApp.getActiveSpreadsheet().getSpreadsheetTimeZone();
var dateString = Utilities.formatDate(ms, spreadsheetTimezone, 'EEE, d MMM yyyy HH:mm:ss');
var date = new Date(dateString);
var epoch = new Date('Dec 30, 1899 00:00:00');
var diff = date.getTime() - epoch.getTime();
x = diff / 1000;
seconds = Math.round(x % 60);
x /= 60;
minutes = Math.round(x % 60);
x /= 60;
hours = Math.round(x % 24);
x /= 24;
days = Math.round(x);
return createMsg(hours, minutes);
}
The function createMsg(...) is omitted because it takes the parameters and create a readable message to the user. The trick here is creating a time range in ms and follow one of the rules to make it seconds/minutes/hours/days or whatever you need.

Calculating runtime minus Timestamp

I have a form which activates a procedure via an "On form submit" trigger. At the end of this routine I want to insert the difference in time between the form's Timestamp and the current time at the end of the routine (the difference of which is only a matter of a few seconds).
I've tried many things so far, but the result I typically receive is NaN.
I thought that my best bet would be to construct the runtime elements (H,M,S) and similarly deconstruct the time elements from the entire Timestamp, and then perform a bit of math on that:
var rt_ts = Math.abs(run_time - ts_time);
(btw, I got that formula from somewhere on this site, but I'm obviously grasping at anything at this point. I just can't seem to find a thread where my particular issue is addressed)
I've always found that dealing with dates and time in Javascript is tricky business (ex: the quirk that "month" start at zero while "date" starts at 1. That's unnecessarily mind-bending).
Would anyone care to lead me out of my current "grasping" mindset and guide me towards something resembling a logical approach?
You can simply add this at the top of your onFormSubmit routine :
UserProperties.setProperty('start',new Date().getTime().toString())
and this at the end that will show you the duration in millisecs.
var duration = new Date().getTime()-Number(UserProperties.getProperty('start'))
EDIT following your comment :
the time stamp coming from an onFormSubmit event is the first element of the array returned by e.values see docs here
so I don't really understand what problem you have ??
something like this below should work
var duration = new Date().getTime() - new Date(e.values[0]).getTime();//in millisecs
the value being a string I pass it it 'new Date' to make it a date object again. You can easily check that using the logger like this :
Logger.log(new Date(e.values[0]));//
It will return a complete date value in the form Fri Mar 12 15:00:00 GMT+01:00 2013
But the values will most probably be the same as in my first suggestion since the TimeStamp is the moment when the function is triggered...
I have a function which can show the times in a ss with timestamps in column A. It will also add the time of the script itself to the first timestamp (in row 3) and show this in the Log.
Notice that the google spreadsheet timestamp has a resolution in seconds and the script timestamp in milliseconds. So if you only add, say, 300 milliseconds to a spreadsheet timestamp, it might not show any difference at all if posted back to a spreadsheet. The script below only takes about 40 milliseconds to run, so I have added a Utilities.sleep(0) where you can change the value 0 to above 1000 to show a difference.
function testTime(){
var start = new Date().getTime();
var values = SpreadsheetApp.getActiveSheet().getDataRange().getValues();
for(var i = 2; i < values.length ; i++){
Logger.log(Utilities.formatDate(new Date(values[i][0]),Session.getTimeZone(),'d MMM yy hh:mm:ss' )); // this shows the date, in my case same as the ss timestamp.
Logger.log( new Date(values[i][0]).getTime() ); // this is the date in Milliseconds after 1 Jan 1970
}
Utilities.sleep(0); //you can vary this to see the effects
var endTime = new Date();
var msCumulative = (endTime.getTime() - start);
Logger.log(msCumulative);
var msTot = (msCumulative + new Date(values[2][0]).getTime());
Logger.log('script length in milliseconds ' + msTot );
var finalTime = Utilities.formatDate(new Date(msTot), Session.getTimeZone(), 'dd/MM/yyyy hh:mm:ss');
Logger.log ( finalTime); //Note that unless you change above to Utilities.sleep(1000) or greater number , this logged date/time is going to be identical to the first timestamp since the script runs so quickly, less than 1 second.
}

How do I parse this back to a mm/dd/yyyy format?

I have some dates in a Google Spreadsheet that I'm bringing in to a script like this:
var JCstartDateFix = Math.floor(Date.parse(JCstartDate) / 86400000) + 25570;
var todaysDateFix = Math.floor(Date.parse(todaysDate) / 86400000) + 25570;
How do I do the opposite of this at the end of the script to change it back into a mm/dd/yyyy formatted date?
Thanks in advance for any help on this.
Here's the whole script:
function projectedDate(JCstartDate, overallPercent, pace, todaysDate, HSstartDate, DaysInHS) {
//converts dates to a number of days
var JCstartDateFix = Math.floor(Date.parse(JCstartDate) / 86400000) + 25570;
var todaysDateFix = Math.floor(Date.parse(todaysDate) / 86400000) + 25570;
//This says that there's no projected date since the student hasn't started high school yet
if(HSstartDate == ""){
return "HS not started";
}
//This calculates grad date if the student's been here more than 8 months or if their percent is over 80.
else if(DaysInHS >= 200 || overallPercent >=80){
var percentPerDay = overallPercent/(DaysInHS);
var daysLeft = (100 - overallPercent) / percentPerDay;
if((todaysDateFix + daysLeft) > (JCstartDateFix +730)){
return "You are not on track to complete.";
}
else{
return (todaysDateFix + daysLeft);
}
}
//This calculates grad date if the student's been at JC less than 8 months
else{
if(JCstartDateFix + 600 - pace > JCstartDateFix + 730){
return "You are not on track to complete.";
}
else{
return (JCstartDateFix+600-pace);
}
}
}
I work in a school where students start at different times and work at their own pace. They have a 2 year limit to finish. So this script estimates their graduation date based on when they started and how fast they're going. It uses different formulas depending on how long they've been here. I'm happy with the dates I get on my spreadsheet, but if I format them from the spreadsheet, another script doesn't correctly pick up the text strings and gives a date in 1969 instead.
I think what I need to do is change the lines that return numbers so that those numbers are formatted as dates. I just don't know how. Thanks again!
The value you get with Date.parse() is in milliseconds, you divide it by the number of milliseconds in a day so I guess you obtain the number of days since the JS reference date, rounded to the lowest integer and then add a constant value of 25570.
What is the result supposed to be ?
It seems that it should be a number of day from the ref date but that's quite far in the future !! (about 70 years) Is this right ? could you clarify ?
Anyway, what you should do is to get a value in milliseconds again and use new Date(value in mSec) to get a date object. From there Utilities.formatDate will allow you to get any display format you want.
ref : http://www.w3schools.com/jsref/jsref_obj_date.asp
https://developers.google.com/apps-script/class_utilities#formatDate
As long as the value that you're setting in the spreadsheet is a Date object in apps script, it will appear as a date. The format will be under the control of the spreadsheet, of course, but it defaults to mm/dd/yyyy.
For example, you could just change your existing code to render Date objects. Then, when you call setValue() you will write a date out to the spreadsheet.
var JCstartDateFix = new Date(Math.floor((Date.parse(JCstartDate) / 86400000) + 25570)*86400000);
var todaysDateFix = new Date(Math.floor((Date.parse(todaysDate) / 86400000) + 25570)*86400000);