Wrong time extraction in google spreadsheets? [duplicate] - javascript

This question already has answers here:
Formatted dates in a Google Apps script
(3 answers)
Closed 7 years ago.
I'm trying to retrieve the time value from google sheet cell via GAS. I put in the cell value (10:30) and get it with the following code (video)
function test_time_getting() {
var sheet, value, p;
sheet = SpreadsheetApp.getActive().getSheetByName('mockup data');
value = sheet.getRange(1,1).getValue();
Logger.log(value);
}
But unexpectedly I received next result in the log:
[15-09-27 05:07:43:784 PDT] Sat Dec 30 10:26:59 GMT+02:27 1899
How it could happen and what to do to retrieve proper time value?

Right time extraction makes by following code:
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);
}
Thus you get the right quantity of seconds then you can calculate quantity of hours and minutes:
seconds = getValueAsSeconds(range);
hours = Math.floor(seconds/3600);
minutes = (seconds/60) % 60;
The answer was found here

Related

Date Math for Google Apps Script for User Submitted Dates

I created a Google Form to collect user input, including the expiration date of a contract.
I need to create a reminder date (6 months before the expiration date) in a new column of the gsheets that is linked to the form. Using the Event Object namedValues, I extracted the expiration date from gsheet. I converted the date to milliseconds and subtracted the number of milliseconds equal to 6 months (or thereabouts). However, the output that got sent back to the googlesheet is an undefined number.
I must be misunderstanding something and was hoping someone more skilled in this can help me out. Is the data type wrong? Thanks for any illumination you can provide.
function onFormSubmit(e) {
var responses = e.namedValues;
var MILLIS_PER_DAY = 1000 * 60 * 60 * 24;
var expireDate = responses['Expiration Date'][0].trim();
var expireDate_ms = expireDate * 1000; // converting to milliseconds
var noticeDate = expireDate_ms - (183 * MILLIS_PER_DAY);
// Create a new column to store the date to send out notice of expiration or renewal
var sheet = SpreadsheetApp.getActiveSheet();
var row = sheet.getActiveRange().getRow();
var column = e.values.length + 1;
sheet.getRange(row, column).setValue(noticeDate);
}
I’d recommend you to use a formula instead:
={"Reminder"; ARRAYFORMULA(IF(NOT(ISBLANK(B2:B)); EDATE(B2:B; -6); ""))}
Add this to the header of an empty column, it will generate all data in that column for you. Change B for the column you have the expiration date on.
If you really need to use Google Apps Script you can, but JavaScript is notorious for having bad date support (at least without an external library). To do it, you’ll have to manually parse the string, modify the date and format it back to the date number:
const dateParts = e.namedValues['Expiration Date'][0].trim().split('/')
const date = new Date(
Number(dateParts[2]), // Year
Number(dateParts[1]) - 1 - 6, // Month. -1 because January is 0 and -6 for the 6 months before
Number(dateParts[0]) // Day
)
const numericDate = Math.floor((date.getTime() - new Date(1900, 0, 1).getTime()) / (1000 * 60 * 60 * 24))
This example only works if the format used in the sheet is DD/MM/YYYY.
The numeral value of date is the number of days since the first day of 1900 (link to documentation). So we need to subtract it and change it from milliseconds to days. Math.floor ensures that it’s not decimal.
You can set numericDate to the cell but make sure the numeric format is Date.
References
EDATE - Docs Editors Help
ARRAYFORMULA - Docs Editors Help
Date - JavaScript (MDN)
DATE - Docs Editor Help
Marti's answer was helpful but the math didn't quite work out because the suggested solution was to minus 6 from the month retrieved. But the reminder date is supposed to be 6 months from the date (taking into account the year and the date), so it doesn't quite work.
The solution I worked out is the following:
function onFormSubmit(e) {
const expireDateParts = e.namedValues['Expiration Date'][0].trim();
if (expireDateParts != ""){
expireDateParts.split('/');
var MILLIS_PER_DAY = 1000 * 60 * 60 * 24;
const expireDate = new Date(
Number(expireDateParts[2]), // Year
Number(expireDateParts[0]) - 1, // Month. -1 because January is '0'
Number(expireDateParts[1]) // Day
);
const reminderNumericDate = Math.floor((expireDate.getTime() - 183 * MILLIS_PER_DAY));
var reminderDate = formatDate(reminderNumericDate);
// Create a new column to store the date to send out notice of expiration or renewal
var sheet = SpreadsheetApp.getActiveSheet();
var row = sheet.getActiveRange().getRow();
var column = 14 // hard-coded to Column 0;
sheet.getRange(row, column).setValue(reminderDate);
// Set up Schedule Send Mail
createScheduleSendTrigger(reminderNumericDate);
var status = 'Scheduled';
sheet.getRange(row, column+1).setValue(status);
}
}

Each day a different item in an array - javascript

I have this script that makes a button redirect to a whatsapp page, on the URL (a href) I need to insert the number that's gonna be contacted.
What I need to do is each day a different number fills this URL.
Example:
day1 - phonen1,
day2 - phonen2,
...,
day 13 - phonen13,
//(starts over)
day14 - phonen1,
day15 - phonen2,
...
<a id="whatsapp" target="_blank" href="https://api.whatsapp.com/send?phone=5519997820734">Link</a>
<script>
phones= ["phonen1", "phonen2", ..., "phonen13"];
document.getElementById("whatsapp").href = "https://api.whatsapp.com/send?phone=5519"+ phones[i] +"";
</script>
you can use the date object with for loop like this:
<a id="whatsapp" target="_blank" href="https://api.whatsapp.com/send?phone=5519997820734">Link</a>
<script>
phones= ["phonen1", "phonen2", ..., "phonen13"];
var d = new Date();
var todayDate = d.getDate();
for (var i = todayDate; i > 13; i= i-13) {
todayDate = todayDate - 13;
}
document.getElementById("whatsapp").href = "https://api.whatsapp.com/send?phone=5519"+phones[i] + todayDate;
</script>
Simple Answer:
You can do this using a Date to count the number of days since the unix epoch, and mod that count by the length of your phones array to get an index that moves to the next item every 24 hours:
let phones = ["phonen1", "phonen2", "phonen3", "phonen4"];
const ms_per_day = 24 * 60 * 60 * 1000;
// (new Date()).getTime() gets the number of ms since 1 January 1970 00:00:00 UTC
// we divide by ms_per_day and floor to get the number of 24-hour cycles (this will increment each UTC day)
let days_since_epoch = Math.floor((new Date()).getTime() / ms_per_day);
// we mod by the length of phones to get a number in the range [0, phones.length)
let phones_index = days_since_epoch % phones.length;
document.getElementById("whatsapp").href = "https://api.whatsapp.com/send?phone=5519" + phones[phones_index];
console.log("Set link to", document.getElementById("whatsapp").href);
<a id="whatsapp" target="_blank" href="https://api.whatsapp.com/send?phone=5519997820734"> Link </a>
Caveats:
Working with time is complicated. The above method doesn't get the number of days exactly:
Due to the differing lengths of days (due to daylight saving changeover), months and years, expressing elapsed time in units greater than hours, minutes and seconds requires addressing a number of issues and should be thoroughly researched before being attempted.
...and the crossover time is in UTC anyway, so it's non-obvious when the above code will switch numbers (it won't be at midnight). But it will do so once every 24 hours, which should be sufficient for the use case described in the post.
One other caveat is that the number won't actually change until the user refreshes the page and reruns the script.
Use the date object to create an index into your array
<a id="whatsapp" target="_blank" href="https://api.whatsapp.com/send?phone=5519997820734">Link</a>
<script>
var phones= ["phone1","phone2","phone3","phone4","phone5","phone6","phone7","phone8","phone9","phone10","phone11","phone12","phone13","phone14"];
var startOfDay1 = new Date('July 1, 2018 00:00:00');//be aware this is the client timezone
var diffFromNow = Date.now() - startOfDay1.getTime();//get the difference in ms between now and midnight of "day 1"
console.log(diffFromNow);
var diffFromNowDays = diffFromNow/(24*60*60*1000);//turn that into a day value
var daynum = Math.floor(diffFromNowDays % 14);//constrain to 14 days
console.log(daynum);//zero based index
document.getElementById("whatsapp").href = "https://api.whatsapp.com/send?phone=5519"+ phones[daynum] +"";
</script>
Ollin's answer is great, but you can use local midnight as follows if you wish. Use the remainder operator % with the number of whole days since a particular point in time, any epoch will do.
If you want to do the changeover at midnight local time, then use local midnight for the epoch and current day. Use Math.round to remove daylight saving effects.
The following will change the value returned from the array at local 00:00:00.001 each day:
// Number of whole local days since date to today
function daysDiff(date) {
// Copy date, set to start of day
var d = new Date(+date);
d.setHours(0,0,0,0);
// Get start of current day
var e = new Date();
e.setHours(0,0,0,0);
// Return whole day count
return Math.round((e - d)/8.64e7);
}
// Select item from array based on number of whole days
// from epoch to today. Default is 1 July 2018
function getFromArray(array, epoch) {
if (!epoch) {
// If not provided, use 1 July 2018
epoch = new Date(2018,6,1);
}
var d = daysDiff(epoch);
return array[d % array.length];
}
var nums = [1,2,3,4,5,6,7,8,9,10,11,12,13,14];
// On local date 12 July 2018 returns 12
console.log(getFromArray(nums));

Getting same unix time stamp for two different times in javascript

I had two ical format timestamps and I want to convert them to normal time first and then to unix time.
Here this is the function I've been using to convert normal time to unix timestamp:
var normal_to_unix = function (date_string) {
var date = new Date(date_string);
return date.getTime() / 1000;
}
This function is fine since date is already in UTC and I need not do any conversions.
Now this is the function I've been using to convert ical time to unix time. The ical time in my case is like "20180603T150000Z".
var ics_to_unix = function (ics_string) {
var year = ics_string.slice(0, 4);
var month = ics_string.slice(4, 6);
var date = ics_string.slice(6, 8);
var hours = ics_string.slice(9, 11);
var minutes = ics_string.slice(11, 13);
var seconds = ics_string.slice(13, 15);
var milliseconds = 0;
console.log(year, month, date, hours, minutes, seconds, milliseconds); // This is example output 2018 06 03 15 00 00 0
return normal_to_unix((new Date(year, month, date, hours, minutes, seconds, milliseconds)).toDateString())
}
Now the problem is I'm getting the same unix time for "20180603T150000Z" and "20180603T160000Z" which are supposed to give different timestamps and it is 1530576000 for both of them.
Is there anything that I'm missing ? Thanks in advance.
Please have a look at this for live example
Several points here:
The toDateString() method returns the date portion of a Date object in human readable form in American English. For your example it is `Tue Jul 03 2018', perhaps that is not what you want.
new Date creates date in your local timezone, which could play well if you use it together with toString(), which will also return the string for date in your local timezone. But it will be subject to daylight saving changes, so I'd avoid using that method.
Another thing I'd like to avoid converting back and forth between strings and dates, since it does a lot of unnecessary computations.
I'd suggest to use the following:
var ics_to_unix = function (ics_string) {
var year = parseInt(ics_string.slice(0, 4));
var month = parseInt(ics_string.slice(4, 6)) - 1; // Jan is 0
var date = parseInt(ics_string.slice(6, 8));
var hours = parseInt(ics_string.slice(9, 11));
var minutes = parseInt(ics_string.slice(11, 13));
var seconds = parseInt(ics_string.slice(13, 15));
return Date.UTC(year, month, date, hours, minutes, seconds) / 1000;
}
I have added explicit conversion of strings to numbers, adjusted the month to match what is used in javascript and also removed the extra call.

moment.js timezone get milliseconds

I'm trying to get number of days passed. I'm storing epoch (milliseconds) for date.
I'm reading startDate from database (date value of first record) in milliseconds and I want to find current epoch in specified timezone.
I tried this:
var startDate = rows[0]['MIN_DATE'];
var endDate = moment().tz("America/New_York");
Then to calculate difference, I used:
var oneDay = 24 * 60 * 60 * 1000;
var daysCount = Math.ceil((endDate - startDate) / (oneDay));
The value of startDate is:
1522821600000 which is: Wednesday, April 4, 2018 2:00:00 AM GMT-04:00 DST
The value of endDate is:
Moment_d: Wed Apr 04 2018 22:24:45 GMT-0400 (EDT)_isAMomentObject: true_isUTC: true_isValid: true_locale: Locale_offset: -240_pf: Object_z: Zone__proto__: Object
The value of daysCount is 2, how?
How can I get milliseconds instead of object from:
moment().tz("America/New_York");
To directly answer your question, use .valueOf() to get the value of moment.tz("America/New_York")
var endDate = moment.tz("America/New_York").valueOf()
I'm having difficulty understanding your question, but I believe you're trying to get the difference between the days considering the correct timezone. The following gives an accurate result using .diff() (https://momentjs.com/docs/#/displaying/difference/)
var timeZone = "America/New_York"
var startDate = 1522821600000
var momentStartDate = moment.tz(startDate,timeZone)
var momentEndDate = moment.tz(timeZone)
alert(momentEndDate.diff(momentStartDate, 'days') );
Use fromNow() function. It is very straight-forward.
Do like this :
moment(date).fromNow();
It will give you number of days passed if date is past as well as number of days to go if date is future.
Below are is example:
var date = 1522821600000; // your date
console.log(moment(date).fromNow());
<script src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.17.1/moment.min.js"></script>
Solved this with following statement:
var endDate = moment().tz("America/New_York").valueOf();

calculate age javascript in adobe acrobat

I am having some difficulties getting a field to populate in an interactive PDF form. I am using a javascript to calculate the current age of client from 2 date fields (DateToday and ClientDOB) already in the form and I need it to populate a "ClientAge" field. The DateToday field automatically populates when the form is opened. I would like for the ClientAge field to populate after the user selects the ClientDOB.
This is what I am trying to have it do. Should be simple I would think.
DateToday - ClientDOB = ClientAge
Here is my code:
var DateToday_ = Date2Num(DateToday.formattedValue, "MM/DD/YYYY")
var ClientDOB_ = Date2Num(ClientDOB.formattedValue, "MM/DD/YYYY")
var diff = DateToday_ - ClientDOB_
ClientAge.value = Floor(diff / 365.25)
I am not sure why the ClientAge field will not populate once the ClientDOB has been selected. Any replies would be helpful. Thanks.
This was taken from somewhere off the 'net. Can' remember where. However I have used this in a number of forms and it works fine. The idea is that the difference between dates is in milliseconds, and a given date is the number of seconds from a fixed date in the past. Once you have the difference in seconds between the dates (in this case DOB to the present) you can calculate how many years that is. Note that my format is in British date format (dd/mm/yy). If you operate in American format (mm/dd/yy) you must make the appropriate changes.
// get current date THIS NON AMERCAN DATE FORMAT
var oNow = new Date();
// get date from 'Demo.DOB' field
var oMyDate = util.scand('dd/mm/yy', this.getField('Demo.DOB').value);
// define second in milliseconds
var nSec = 1000;
// define minute in milliseconds
var nMin = 60 * nSec;
// define hour in milliseconds
var nHr = 60 * nMin;
// define day in milliseconds
var nDay = 24 * nHr;
// compute today as number of days from epoch date
var nNowDays = Number(oNow) / nDay;
// truncate to whole days
nNowDays = Math.floor(nNowDays);
// compute inputted date days from epoch data
var nMyDateDays = Number(oMyDate) / nDay;
// truncate to whole days
nMyDateDays = Math.floor(nMyDateDays);
// compute difference in the number of days
var nDiffDays = nNowDays - nMyDateDays;
// adjust difference for counting starting day as 1
++nDiffDays;
// convert days to years
var nYears = nDiffDays / 365.2525
// truncate to whole years
nYears = Math.floor(nYears);
// set field value number of years (nYears)
event.value = nYears;

Categories

Resources