Apps Script JDBC reads DATETIME with wrong timezone - google-apps-script

I'm trying to read from a DATETIME field in MySQL using the Apps Script JDBC service. The database has its timezone set to UTC (##global.time_zone == ##session.time_zone == '+00:00'), and I've double-checked this by doing SELECT UNIX_TIMESTAMP(COL) FROM TABLE. My script is also set to use UTC.
However, when I read the value from the JDBC result set using getTimestamp, it is skewed forwards by 8 hours. This occurs regardless of whether I pass a timezone to getTimestamp (indeed, there is no change whatsoever, regardless of what timezone I pass), and regardless of whether useJDBCCompliantTimeZoneShift is enabled or not.
If I read the result using getString, it gives the correct time (in UTC). Barring using getString and parsing it into a JavaScript Date, how can I fix this issue?
Edit
Here's a testing script I used, and its output:
export function tzTest(): void {
const dbIp = DB_IP
const dbPw = DB_PW
let conn = Jdbc.getConnection(`jdbc:mysql://${dbIp}/mydb`, { user: "myuser", password: dbPw })
let stmt = conn.prepareStatement("SELECT COL FROM MYTABLE WHERE OWNER_ID=1")
stmt.execute()
let res = stmt.getResultSet()
res.next()
console.log("==== DEFAULT ====")
console.log("=== getTimestamp ===")
console.log(`plain: ${new Date(res.getTimestamp(1).getTime())} (${res.getTimestamp(1).getTime()})`)
console.log(`utc: ${new Date(res.getTimestamp(1, "UTC").getTime())} (${res.getTimestamp(1, "UTC").getTime()})`)
console.log("=== getTime ===")
console.log(`plain: ${new Date(res.getTime(1).getTime())} (${res.getTime(1).getTime()})`)
console.log(`utc: ${new Date(res.getTime(1, "UTC").getTime())} (${res.getTime(1, "UTC").getTime()})`)
console.log("=== getDate ===")
console.log(`plain: ${new Date(res.getDate(1).getTime())} (${res.getDate(1).getTime()})`)
console.log(`utc: ${new Date(res.getDate(1, "UTC").getTime())} (${res.getDate(1, "UTC").getTime()})`)
conn.close()
conn = Jdbc.getConnection(`jdbc:mysql://${dbIp}/mydb`, { user: "myuser", password: dbPw, useJDBCCompliantTimeZoneShift: true })
stmt = conn.prepareStatement("SELECT COL FROM MYTABLE WHERE OWNER_ID=1")
stmt.execute()
res = stmt.getResultSet()
res.next()
console.log("==== useJDBCCompliantTimeZoneShift ====")
console.log("=== getTimestamp ===")
console.log(`plain: ${new Date(res.getTimestamp(1).getTime())} (${res.getTimestamp(1).getTime()})`)
console.log(`utc: ${new Date(res.getTimestamp(1, "UTC").getTime())} (${res.getTimestamp(1, "UTC").getTime()})`)
console.log("=== getTime ===")
console.log(`plain: ${new Date(res.getTime(1).getTime())} (${res.getTime(1).getTime()})`)
console.log(`utc: ${new Date(res.getTime(1, "UTC").getTime())} (${res.getTime(1, "UTC").getTime()})`)
console.log("=== getDate ===")
console.log(`plain: ${new Date(res.getDate(1).getTime())} (${res.getDate(1).getTime()})`)
console.log(`utc: ${new Date(res.getDate(1, "UTC").getTime())} (${res.getDate(1, "UTC").getTime()})`)
conn.close()
}
This results in the following output:
==== DEFAULT ====
=== getTimestamp ===
plain: Sat Dec 21 2019 15:39:17 GMT+0000 (Coordinated Universal Time) (1576942757000)
utc: Sat Dec 21 2019 15:39:17 GMT+0000 (Coordinated Universal Time) (1576942757000)
=== getTime ===
plain: Thu Jan 01 1970 15:39:17 GMT+0000 (Coordinated Universal Time) (56357000)
utc: Thu Jan 01 1970 15:39:17 GMT+0000 (Coordinated Universal Time) (56357000)
=== getDate ===
plain: Sat Dec 21 2019 08:00:00 GMT+0000 (Coordinated Universal Time) (1576915200000)
utc: Sat Dec 21 2019 00:00:00 GMT+0000 (Coordinated Universal Time) (1576886400000)
==== useJDBCCompliantTimeZoneShift ====
=== getTimestamp ===
plain: Sat Dec 21 2019 15:39:17 GMT+0000 (Coordinated Universal Time) (1576942757000)
utc: Sat Dec 21 2019 15:39:17 GMT+0000 (Coordinated Universal Time) (1576942757000)
=== getTime ===
plain: Thu Jan 01 1970 15:39:17 GMT+0000 (Coordinated Universal Time) (56357000)
utc: Thu Jan 01 1970 15:39:17 GMT+0000 (Coordinated Universal Time) (56357000)
=== getDate ===
plain: Sat Dec 21 2019 08:00:00 GMT+0000 (Coordinated Universal Time) (1576915200000)
utc: Sat Dec 21 2019 00:00:00 GMT+0000 (Coordinated Universal Time) (1576886400000)
For comparison, SELECT COL,(UNIX_TIMESTAMP(COL) * 1000) FROM MYTABLE WHERE OWNER_ID=1 gives 2019-12-21 07:39:17 and 1576913957000.

This issue seems to be a bug in the past and should already be fixed.
Including useJDBCCompliantTimezoneShift=true in the connection parameter should fix the issue to interpret the timezone correctly.
Noting here that the timezone shown when converting a JavaScript Date to a string will always be the timezone of the server (in this case UTC) that's why your workaround fixed it.

Related

Unable to match an mysql string response in freeradius

I using freeradius 2.2.8 and mysql for sending our coa/disconnect messages via freeradius when a bandwidth quota is hit. That part of the code is working great. Unfortunately for me the coa/disconnect message is sent out even though an Accounting Stop is sent out by the NAS. In order to prevent that from happening I am putting a condition where in I pull the acct termination cause from mysql radacct table and compare it against some strings.
Under accounting,
update control {
....
Tmp-String-0 := "%{sql:SELECT acctterminatecause AS Terminate FROM radacct WHERE radacct.username='%{User-Name}' AND radacct.acctsessionid='%{Acct-Session-Id}'}}"
***if ("%{control:Tmp-String-0}" != "User-Request")***{
if (("%{control:Tmp-Integer-0}" > "%{control:Tmp-Integer-2}") || ("%{control:Tmp-Integer-1}" > "%{control:Tmp-Integer-3}")){
if ("%{control:coa_dm}" == "coa"){
update coa {
User-Name = "%{User-Name}"
Acct-Session-Id = "%{Acct-Session-Id}"
NAS-IP-Address = "%{NAS-IP-Address}"
#Filter-Id = "UN-AUTHORIZED-PROFILE"
Framed-IP-Address = "%{Framed-IP-Address}"
Session-Timeout = 10
}
}
if ("%{control:coa_dm}" == "dm"){
update disconnect {
User-Name = "%{User-Name}"
NAS-IP-Address = "%{NAS-IP-Address}"
}
}
}
}
As per the freeradius debug logs we can see that the string should be a match and the program should avoid the inside if conditions. Unfortunately that is not the case and the 1st IF condition always returns true.
***Thu May 17 17:43:41 2018 : Info: expand: SELECT acctterminatecause AS Terminate FROM radacct WHERE radacct.username='%{User-Name}' AND radacct.acctsessionid='%{Acct-Session-Id}' -> SELECT acctterminatecause AS Terminate FROM radacct WHERE radacct.username='kiranc' AND radacct.acctsessionid='5AFD71CB-3FE1C000'
Thu May 17 17:43:41 2018 : Debug: rlm_sql (sql): Reserving sql socket id: 16
Thu May 17 17:43:41 2018 : Info: sql_xlat finished
Thu May 17 17:43:41 2018 : Debug: rlm_sql (sql): Released sql socket id: 16
Thu May 17 17:43:41 2018 : Info: expand: %{sql:SELECT acctterminatecause AS Terminate FROM radacct WHERE radacct.username='%{User-Name}' AND radacct.acctsessionid='%{Acct-Session-Id}'}} -> User-Request}
Thu May 17 17:43:41 2018 : Info: ++} # update control = noop
Thu May 17 17:43:41 2018 : Info: ++? if ("%{control:Tmp-String-0}" != "User-Request")
Thu May 17 17:43:41 2018 : Info: expand: %{control:Tmp-String-0} -> User-Request}
Thu May 17 17:43:41 2018 : Info: ? Evaluating ("%{control:Tmp-String-0}" != "User-Request") -> TRUE***
Thu May 17 17:43:41 2018 : Info: ++? if ("%{control:Tmp-String-0}" != "User-Request") -> TRUE
Thu May 17 17:43:41 2018 : Info: ++if ("%{control:Tmp-String-0}" != "User-Request") {
Thu May 17 17:43:41 2018 : Info: +++? if (("%{control:Tmp-Integer-0}" > "%{control:Tmp-Integer-2}") || ("%{control:Tmp-Integer-1}" > "%{control:Tmp-Integer-3}"))
Thu May 17 17:43:41 2018 : Info: expand: %{control:Tmp-Integer-0} -> 3169
Thu May 17 17:43:41 2018 : Info: expand: %{control:Tmp-Integer-2} -> 25000000
Thu May 17 17:43:41 2018 : Info: ?? Evaluating ("%{control:Tmp-Integer-0}" > "%{control:Tmp-Integer-2}") -> FALSE
Thu May 17 17:43:41 2018 : Info: expand: %{control:Tmp-Integer-1} -> 13402
Thu May 17 17:43:41 2018 : Info: expand: %{control:Tmp-Integer-3} -> 50000000
I tried the single quotes, double quotes using the & instead of %, but to no avail. The other conditions are met correctly when hit as they are returned as integers.
Thank you for the help.
I forgot to mention that I had got it working. Instead of comparing using Tmp-String-0 variable I just used the actual radius attribute name and got it working.
if (("%{Acct-Terminate-Cause}" != "User-Request")
Thank you for the help.

How to fetch JSON content values dynamically using JSON slurper in groovy

I am trying to filter out the JSON response values by passing on few parameters dynamically. Below is the code.
import com.eviware.soapui.support.XmlHolder
import groovy.json.JsonSlurper
responseContent = testRunner.testCase.getTestStepByName("Request 1").getPropertyValue("Response")
jsonresponse = new JsonSlurper().parseText(responseContent)
log.info jsonresponse.context["parameter"]
context["parameter"] stores the values from an Excel sheet and doing only a log.info for context["parameter"], it shows those values correctly. Below is the output of the code log.info context["parameter"].
Thu Dec 14 07:18:53 CST 2017:INFO:firstName
Thu Dec 14 07:18:53 CST 2017:INFO:lastName
Thu Dec 14 07:18:54 CST 2017:INFO:frNum
Thu Dec 14 07:18:54 CST 2017:INFO:notes
But when I execute the code
log.info jsonresponse.context["parameter"]
Result:
Thu Dec 14 07:20:41 CST 2017:INFO:[]
Thu Dec 14 07:20:41 CST 2017:INFO:[]
Thu Dec 14 07:20:41 CST 2017:INFO:[]
Thu Dec 14 07:20:42 CST 2017:INFO:[]
Thu Dec 14 07:20:42 CST 2017:INFO:[]
log.info jsonresponse yields the below response out of which I need to get certain values (values stored in the context["parameter"])
Thu Dec 14 07:21:45 CST 2017:INFO:[{errorMessage=null, middleName=null, lastName=Kosnick, frName=Kosnick Steven H , mplastName=null, competeRgnTxt=null, doNum=null, gddUnitStDate=null, fdNum=null, mpfirstName=null, legalEntityID=null, noNum=null, contractType=Financial Rep, frNum=046426, offcNum=NO 091, notes=Active, fullTmeSrvDt=null, firstName=Steven, networkOfficeNum=091}]
Instead of this :
log.info jsonresponse.context["parameter"]
Try this :
log.info jsonresponse[context["parameter"]]
This should resolve your issue :)

To get values from 2D array

I have used this query to retrieve the dates for one particular user's approved leaves -
LeaveRequest.where(user_id: 6).where(status: 1).pluck(:from_date, :to_date)
and I'm getting this array as result -
[[Mon, 12 Sep 2016, Fri, 16 Sep 2016], [Tue, 06 Sep 2016, Tue, 06 Sep 2016], [Thu, 01 Sep 2016, Fri, 02 Sep 2016], [Tue, 30 Aug 2016, Wed, 31 Aug 2016]]
what I want is to fetch all the dates as well as the dates between 12 Sep 2016 and 16 Sep, 2016 (13th 14th and 15th).
I am assuming you mean something like this
require 'date'
#This is to simulate your current Array
current_array = 5.times.map {|n [Date.new(2016,n+1,1).<<(1),Date.new(2016,n+1,1)]}
#map the 2 dates to a Range
new_array = current_array.map{|start_date,end_date| (start_date..end_date)}
new_array.first.class
#=> Range
Calling to_a on the Range will blow it out into all the dates between start_date and end_date
With a rails you could do something like
class LeaveRequest
def self.user_requested_ranges(user_id, status_id)
scoped.
where(user_id: user_id, status: status_id).
pluck(:from_date, :to_date).
map do |from_date, to_date|
#optionally to output the full Array in each Range you could use
#(from_date..to_date).to_a
(from_date..to_date)
end
end
end
Then call as
LeaveRequest.user_requested_ranges(6,1)

Haskell: count an enum (Days of week) by an int

I want to create a function for a calender programm, that does the following:
proceed :: Day -> Int -> Day
> proceed Mon 9
Wed
The function proceed should tell me, what weekday it is in 9 days, if today is Monday.
Now I try this:
data Day = Mon | Tue | Wed | Thu | Fri | Sat | Sun deriving Show
next :: Day -> Day
next Mon = Tue
next Tue = Wed
next Wed = Thu
next Thu = Fri
next Fri = Sat
next Sat = Sun
next Sun = Mon
proceed :: Day -> Int -> Day
proceed d a = if a==0 then next d
else proceed (next d) (a-1)
I try :
proceed Mon 9
Thu
But that's wrong, the right answear is Wed!!!!!!!
I don't know where I've made the mistake.
Thanks to bheklilr
if a == 0 then d else proceed (next d) (a-1)
It was only an off by one error!

Dealing with empty cells in Google Apps Script

Why doesn't this work?
function sendDuesReminder() {
var paid = 3;
var name = 1;
var submitted = 0;
var allowance = 9;
var ms = 86400000; // Number of milliseconds in a day
var today = new Date();
var reminder = 72;
var data = SpreadsheetApp.openById('___').getSheetByName('Master').getDataRange().getValues();
for (var i = 1; i < data.length; i++) {
if (data[i][paid] != 'Yes' &&
data[i][paid] != 'yes' &&
data[i][reminder] == '' &&
((((today.valueOf()) - (data[i][submitted].valueOf()))/ms) > allowance)) {
MailApp.sendEmail("___", "___") ;
SpreadsheetApp.openById('___').getSheetByName('Master').getRange(i+1, reminder).setValue(today);
}
if (data[i][paid] != 'Yes' &&
data[i][paid] != 'yes' &&
data[i][reminder] != null &&
((((today.valueOf()) - (data[i][reminder].valueOf()))/ms) > allowance)) {
MailApp.sendEmail("___", "___") ;
SpreadsheetApp.openById('___').getSheetByName('Master').getRange(i+1, reminder).setValue(today);
}
SpreadsheetApp.flush();
}
Browser.msgBox("OK. Reminder e-mails have been sent. !")
}
What I really want to do is say send the e-mail if column BT is empty OR if the date in column BT is older than 9 days. But I didn't know how to include an or statement within the if statement. So I just set up two separate if statements.
When I use '', though, for the second if statement, I get an error saying that it can't get the value of something that's undefined.
When I use null or undefined, it doesn't work.
Anybody have any thoughts?
Are you sure you have 72 columns in your spreadsheet ? when you use data[i][reminder] == '' the error returned concerns the first term of the equal, not the second... so I guess data doesn't have 72 secondary index and this is returning an error.
(EDIT : to be more clear : you cannot get the value of an undefined item using .valueOf and divide it by something, that's why you get "an error saying that it can't get the value of something that's undefined ".)
If you want to learn about how to implement OR statement you can have a look at w3school, 'Comparison Operators'
Note that you can compare date object directly, you don't need to convert them to milliseconds explicitely, javascript does it internally.
here is an example of how you could write this shortly
var tendaysBefore = new Date(new Date().getTime()-10*24*60*60*1000);// 10 days before
if (data[i][paid].toLowerCase() != 'yes' && (data[i][reminder] == ''||(data[i][reminder] == null || data[i][submitted]< tendaysBefore)) { // not 'yes' and one of the 3 other conditions
MailApp.sendEmail("___", "___") ;
SpreadsheetApp.openById('___').getSheetByName('Master').getRange(i+1, reminder).setValue(today);
}
So here's the code for the loop I tried based on Serge's very kind initial thought.
for (var i = 1; i < data.length; i++) {
if (data[i][paid].toLowerCase() != 'yes' &&
(data[i][submitted]<tendaysBefore &&
(data[i][reminder] == ''||
data[i][reminder] == null))) {
MailApp.sendEmail("___", "Reminder About Dues for Newcomers & Neighbors", "___") ;
SpreadsheetApp.openById('___').getSheetByName('Master').getRange(i+1, reminder).setValue(today);
}
SpreadsheetApp.flush();
}
I changed the order of the if statement because I'm not sure I've adequately articulated in English what I'm trying to get it to do.
What I WANT it to say is IF they haven't paid AND 10 days have passed since they submitted their form AND EITHER the reminder cell is blank or has a null value, THEN send the e-mail.
(Once I get THIS statement working, I'll go on to say if 10 days go by after we send the first e-mail and they STILL haven't paid, we send another e-mail. That's why I'm going through all this machination to put a date in reminder rather than just something like "sent".)
The code I have works. EXCEPT, if you run it, send out the first batch of e-mails, let it add today's date to reminder, and then run it again, it sends the e-mails out all over again.
In short,
(data[i][reminder] == ''||
data[i][reminder] == null))
doesn't seem to be accomplishing what is supposed to do, which is make the if statement fail for any row that has ANYTHING in the reminder column. That's why I initially came at this with "how do I deal with empty cells"? Because--for the life of me, I can't understand why
(data[i][reminder] == ''||
data[i][reminder] == null))
isn't bulletproof.
As I suggested in my comment to Serge's answer, this is starting to make me crazy. I, therefore, cannot thank anybody enough for ANY thoughts you have. Thanks in advance!
In response to Serge's question that I capture some values from the log, here's the output from the log after I added his requested code to the loop:
Paid=yes date subm=Sat Jun 02 2012 14:44:27 GMT-0400 (EDT)reminder=undefined
Paid=yes date subm=reminder=undefined
Paid=yes date subm=reminder=undefined
Paid=yes date subm=reminder=undefined
Paid=yes date subm=reminder=undefined
Paid=yes date subm=reminder=undefined
Paid=yes date subm=reminder=undefined
Paid=yes date subm=reminder=undefined
Paid=yes date subm=reminder=undefined
Paid=yes date subm=reminder=undefined
Paid=yes date subm=reminder=undefined
Paid=yes date subm=Wed Jun 27 2012 16:22:35 GMT-0400 (EDT)reminder=undefined
Paid=yes date subm=Fri Jun 29 2012 09:07:21 GMT-0400 (EDT)reminder=undefined
Paid=yes date subm=Mon Jul 09 2012 10:11:20 GMT-0400 (EDT)reminder=undefined
Paid=yes date subm=Mon Jul 09 2012 10:16:56 GMT-0400 (EDT)reminder=undefined
Paid= date subm=Mon Jul 09 2012 10:17:00 GMT-0400 (EDT)reminder=undefined
Paid=yes date subm=Mon Jul 09 2012 10:26:36 GMT-0400 (EDT)reminder=undefined
Paid=yes date subm=Mon Jul 09 2012 10:30:23 GMT-0400 (EDT)reminder=undefined
Paid=yes date subm=Mon Jul 09 2012 11:02:19 GMT-0400 (EDT)reminder=undefined
Paid= date subm=Mon Jul 09 2012 12:33:57 GMT-0400 (EDT)reminder=undefined
Paid=yes date subm=Mon Jul 09 2012 13:48:54 GMT-0400 (EDT)reminder=undefined
Paid= date subm=Mon Jul 09 2012 18:19:22 GMT-0400 (EDT)reminder=undefined
Paid= date subm=Mon Jul 09 2012 21:07:05 GMT-0400 (EDT)reminder=undefined
Paid= date subm=Mon Jul 09 2012 21:44:13 GMT-0400 (EDT)reminder=undefined
Paid= date subm=Mon Jul 09 2012 21:53:55 GMT-0400 (EDT)reminder=undefined
Paid= date subm=Tue Jul 10 2012 11:09:03 GMT-0400 (EDT)reminder=undefined
Paid= date subm=Tue Jul 10 2012 12:57:41 GMT-0400 (EDT)reminder=undefined
Paid=yes date subm=Wed Jul 11 2012 18:36:49 GMT-0400 (EDT)reminder=undefined
Paid= date subm=Thu Jul 12 2012 07:14:53 GMT-0400 (EDT)reminder=undefined
Paid=yes date subm=Tue Jul 17 2012 14:54:16 GMT-0400 (EDT)reminder=undefined
Paid=yes date subm=Wed Jul 18 2012 20:26:23 GMT-0400 (EDT)reminder=undefined
Paid= date subm=Thu Jul 19 2012 13:43:09 GMT-0400 (EDT)reminder=undefined
I have no idea what to make of this, but I'm sure smarter people than I do see something interesting here?
OK, following Serge's diligent trouble shooting with me, here's the code that worked for this problem. Many, MANY thanks to Serge!
function sendDuesReminder() {
var paid = 3;
var name = 1;
var submitted = 0;
var allowance = 9;
var ms = 86400000; // Number of milliseconds in a day
var today = new Date();
var reminder = 72;
var reminderArray = reminder - 1;
var tendaysBefore = new Date(new Date().getTime()-10*24*60*60*1000);
var data = SpreadsheetApp.openById('___').getSheetByName('Master').getDataRange().getValues();
for (var i = 1; i < data.length; i++) {
if (data[i][paid].toLowerCase() != 'yes' &&
(data[i][submitted]<tendaysBefore &&
(data[i][reminderArray] == ''||
data[i][reminderArray] == null))) {
MailApp.sendEmail("___", "___", "___") ;
SpreadsheetApp.openById('___').getSheetByName('Master').getRange(i+1, reminder).setValue(today);
}
SpreadsheetApp.flush();
Logger.log('Paid='+data[i][paid].toLowerCase()+' date subm='+data[i][submitted]+'reminder='+data[i][reminder])
}
Browser.msgBox("OK. Reminder e-mails have been sent. !")
}