Spring Scheduled annotation with zone EST, not working - spring

I am trying to create a scheduler to run in EST timezone. For that, I have added #Scheduled annotation upon the scheduled method. The method is given below. I want this method to run daily at 05:00 am EST on Mon-Friday, but it runs at 3:30 am IST (6:00 pm EST).
#Scheduled(cron = "0 0 5 * * MON-FRI", zone = "EST")
public void jobRunDaily() {
logger.info("jobRunDaily : called");
this.sendEmailDaily();
}

As described in the documentation, zone accepts IDs that are valid for TimeZone.getTimeZone(String).
In TimeZone documentation you will find the following for such method:
the ID for a TimeZone, either an abbreviation such as "PST", a full name such as "America/Los_Angeles", or a custom ID such as "GMT-8:00". Note that the support of abbreviations is for JDK 1.1.x compatibility only and full names should be used.
Meaning that full names should be used instead of your "EST" abbreviation.

Related

changed laravel app timezone, time got from db did not change

Assume having a Eloquent model called Request with the column next_check autocasted as date (protected $dates = ['next_check'];).
APP_TIMEZONE is initial Europe/Helsinki (+02:00)
$ artisan tinker
Psy Shell v0.10.4 (PHP 7.4.11 — cli) by Justin Hileman
>>> $pr = Request::find(1);
>>> $pr->next_check = Carbon\Carbon::now();
>>> $pr->save();
>>> Request::find(1)->next_check;
=> Illuminate\Support\Carbon #1603973824 {#2900
date: 2020-10-29 14:17:04.0 Europe/Helsinki (+02:00),
}
That looks all fine and we saved 14:17:04 assuming we're in Helsinki.
Now changing the timezone to Europe/Berlin (+01:00), I would assume to get 13:17:04 returned.
>>> Request::find(1)->next_check;
=> Illuminate\Support\Carbon #1603977424 {#2900
date: 2020-10-29 14:17:04.0 Europe/Berlin (+01:00),
}
The timezone is changed but still there is the time returned, which was originally saved in Europe/Helsinki time.
Is that an expected behaviour and how can I get my desired behaviour that a change of the app timezone would result in converted times?
p.s.: the db timezone configured in laravel is still the default '+00:00'
If you want to localise times so they show to user in the user's timezone, you need to CONVERT an existing datetime:
$users_timezone = 'Europe/Berlin';
$datetime->setTimezone($users_timezone);
This will actually change the time according to the difference between the app's timezone and the one converted to.
To get my expected behaviour, I now found a solution. If anybody else want's that exact same behaviour, this might be the solution:
Add the following call in your AppServiceProvider's boot-method:
$this->setUTCOffsetInDBConnection();
The setUTCOffsetInDBConnection method's code is as following:
// according to https://www.sitepoint.com/synchronize-php-mysql-timezone-configuration/
private function setUTCOffsetInDBConnection() {
$now = new \DateTime();
$mins = $now->getOffset() / 60;
$sgn = ($mins < 0 ? -1 : 1);
$mins = abs($mins);
$hrs = floor($mins / 60);
$mins -= $hrs * 60;
$offset = sprintf('%+d:%02d', $hrs*$sgn, $mins);
DB::statement("SET time_zone='".$offset."';");
}
This will always synchronize the timezone according to your app's timezone and save the timestamps as UTC in the database.
When you now save a timestamp 2020-10-29 15:28:00 from your app with APP_TIMEZONE=Europe/Berlin in your .env, it will save it as UTC in the database (2020-10-29 15:28:00).
When you change your APP_TIMEZONE to Europe/Helsinki now, you will get 2020-10-29 16:28:00 returned.
Be aware that your phpMyAdmin might still not show the saved UTC times in your database since also phpMyAdmin sets the servers timezone when opening the connection. So if your server which runs phpMyAdmin is also in Europe/Berlin, you will see 2020-10-29 15:28:00 and not the UTC date saved in the DB.
Answer to "Is that an expected behaviour" is YES
To "save" the timezone with the date data, you have to save it too as an extra column.
So having both "2020-10-29 14:17:04.0" and "Europe/Helsinki" in DB will allow you to remember what timezone was used to save this date, so if it's changed, you can convert.
But first you should consider not to change your app and DB timezone, both should remain UTC.
See https://medium.com/#kylekatarnls/always-use-utc-dates-and-times-8a8200ca3164
So so you can easily convert them into any timezone and display it properly according to the user timezone while keeping a standard well-known format in DB.

What is the Zone Id for GMT in Java 8

I want to get the difference in seconds to find whether the system timezone is ahead or behind the remote timezone. Here the remote timezone value is "GMT" which i fetch from Database. It could be "US/Eastern", which i convert to "America/New_York". But for GMT, im getting ERROR.
ZoneId.systemDefault().getRules().getOffset(Instant.now()).getTotalSeconds()
- ZoneId.of("GMT").getRules().getOffset(Instant.now()).getTotalSeconds()
But it gives the following error,
Exception in thread "main" java.time.DateTimeException: Invalid ID for ZoneOffset, invalid format:
at java.time.ZoneOffset.of(Unknown Source)
at java.time.ZoneId.of(Unknown Source)
at java.time.ZoneId.of(Unknown Source)
How to resolve this error ?
What to use in place of GMT ??
Use Etc/UTC
import java.time.Instant;
import java.time.ZoneId;
public class Main {
public static void main(String args[]) {
System.out.println(ZoneId.of("Etc/UTC").getRules().getOffset(Instant.now()).getTotalSeconds());
}
}
Output:
0
The official answer is:
Etc/GMT
It’s the same as the Etc/UTC suggested in the other answers except for the name.
For the sake of completeness there are a number of aliases for the same, many of them deprecated, not all. You can find them in the link.
And I am not disagreeing with the comments telling you to prefer UTC. I just wanted to answer the question as asked.
For your case you should not need to ask at all though. ZoneId.of("GMT").getRules().getOffset(Instant.now()).getTotalSeconds() should always yield 0, so there is no need to subtract anything. I would either insert a comment why I don’t or subtract a well-named constant with the value 0.
Link: List of tz database time zones
It's ZoneId.of("UTC")...
Here's evidence:
public static void main(String[] args) {
// define the ZoneId
ZoneId utc = ZoneId.of("UTC");
// get the current date and time using that zone
ZonedDateTime utcNow = ZonedDateTime.now(utc);
// define a formatter that uses O for GMT in the output
DateTimeFormatter gmtStyleFormatter = DateTimeFormatter
.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSS O");
// and print the datetime using the default DateTimeFormatter and the one defined above
System.out.println(utcNow + " == " + utcNow.format(gmtStyleFormatter));
}
output (some moments ago):
2020-09-16T08:02:34.717Z[UTC] == 2020-09-16T08:02:34.717 GMT
Getting the total zone offset in seconds of this zone by
utc.getRules().getOffset(Instant.now()).getTotalSeconds();
will result in 0, because this zone has no offset.

Google calendar API ruby, datetime timezone

I have this code. which creates a event in my google calendar.
client = Signet::OAuth2::Client.new(client_options)
client.update!(session[:authorization])
service = Google::Apis::CalendarV3::CalendarService.new
service.authorization = client
event = Google::Apis::CalendarV3::Event.new({
start: Google::Apis::CalendarV3::EventDateTime.new(
date_time: cf_event.starts_at.to_datetime.rfc3339,
time_zone: 'America/Monterrey'
),
end: Google::Apis::CalendarV3::EventDateTime.new(
date_time: cf_event.ends_at.to_datetime.rfc3339,
time_zone: 'America/Monterrey'
),
summary: cf_event.title
})
It is a basic example my cf_event object has the starts_at attr, which is a timeWithZone.
so i had to do cf_event.starts_at.to_datetime.rfc3339.
Output
"2019-03-15T17:50:00+00:00"
The problem is, that the code creates, the event but with -6 hours.
If i go to google calendars my event it´s the day 15 at (11 - 11:50), and not (17 - 17:50)
what am i doing wrong?
You are inputting the time as 17:50:00 in UTC+0 (the +00:00 from your date_time stands for UTC or UTC+0), however, you specified a time_zone where you used Monterrey which follows the time zone UTC-6.
My guess here is that, your code takes 17:50:00 in UTC+0 then converts it to Monterrey time zone UTC-6 which results to 11:50:00. Either try removing the +00:00 or try making it -06:00.

Spring Boot scheduled task running for entire hour rather than at the hour

Spring Boot here. I have the following scheduled task:
#Component
public class AdminWatchdog {
#Autowired
private EmailService emailService;
// Ctors, getters & setters here
#Scheduled(cron = "'* * */12 * * *")
public void runReports() {
// Doesn't matter what it does, really
}
}
When I run this, it appears to be firing either every minute or every second (can't tell based on the logs) for the entire duration of the 12th hour of every day!
I only want this task to run one time every day at noon (12 pm). Is the Spring cron configured incorrectly or do I have something else going on in my app perhaps??
Your cron is incorrect. For running your job every noon every day use this
"0 0 12 * * ?"
The expression is very self explainatory if you understand what each character represent
0 0 12 * * ?
<second> <minute> <hour> <day-of-month> <month> <day-of-week>
For your reference. You can make use of tools like http://www.cronmaker.com/ to design your cron

Sinatra/Ruby time zone troubles between development & production

My Sinatra app is creating a simple object and persisting it to Postgres:
post '/' do
event = Event.new(params)
event.created_at = Time.now.utc
event.date = next_date(params[:dayofweek], params[:time]) if params[:dayofweek] && params[:time]
if event.save
status 201
event.to_json
else
json_status 400, event.errors.to_hash
end
def next_date(dayofweek, hour)
...
# some calculations that effectively culminate in the final line below
...
my_time = Time.utc(2012, 11, 9, 12, 0, 0) ## => 2012-11-09 12:00:00 UTC
end
Object saves successfully. But when I retrieve the object from my development environment I get (json):
{ ..., "date":"2012-11-23T20:00:00-08:00" } #notice the PST offset of -08:00.
I'm expecting the UTC time zone or +00:00. For some reason my development workstation, which is in PST, is factoring in its own time zone when saving to Postgres...at least that what it appears to be doing?!?
Sending the same code to the production server (Heroku) stores same data with proper offset of +00:00
How can I make my development workstation act like the production one? Or, how should I be creating a proper UTC Date object in Sinatra?
First verify that your data does a round-trip successfully:
event.created_at = Time.now.utc
event.date = ...whatever...
tmp_created_at = event.created_at
tmp_date = event.date
event.save
event.reload!
tmp_created_at == event.created_at or raise "created_at failed"
tmp_date == event.date_at or raise "date failed"
Second, verify that the JSON is accurate.
compare the JSON time string to the expected time
the JSON time string has the -08:00
is the JSON string the same actual time?
For example, if you expect 10:00Z, does the JSON show 02:00-08:00 (i.e. the same actual time) or 10:00-08:00 (not the same actual time-- this is eight hours later).
If the data round-trip works, and the JSON is the same actual time, then look at whatever JSON library you're using to print the strings. Look for a method like "iso8601" that will print the time in standard UTC format.
Also, it may be helpful to know that Postgres saves timestamps without the time zone by default.
"The SQL standard requires that writing just timestamp be equivalent to timestamp without time zone, and PostgreSQL honors that behavior. (Releases prior to 7.3 treated it as timestamp with time zone.) timestamptz is accepted as an abbreviation for timestamp with time zone; this is a PostgreSQL extension."
You can see this by describing the table, which may look something like this:
# \d events
Table "public.events"
Column | Type | Modifiers
-----------+-----------------------------+-----------------------------------
id | integer | not null default
name | character varying(255) |
created_at | timestamp without time zone | not null
updated_at | timestamp without time zone | not null
date | timestamp with time zone | not null
More info based on OP's feedback...
OP says: I'm using DataMapper and after digging around on their site I found "time properties will always be stored and retrieved in the timezone the datastore is set to" and a link to a gem that'll force a specific zone.
Because the round-trip shows a problem, try using a current version of the connection library e.g. a current DataMapper, and also try a current version of any similar library e.g. ActiveRecord (version 3.2.8 at the time of this writing).

Resources