Setting quartz schedule with startdate and timezone - quartz-scheduler

I have the following method to schedule a job to fired at different timezone and start date.
If the server's timezone is Asia/Taipei, and the schedule is set to the following inputs:
triggerName="testTrigger",
jobName="testJob",
group="testGroup",
startDate = 2014-12-03 18:00:00
timezoneString = "Austrailia/Melbourne"
cronExp = 0 0/1 * 1/1 * ? *
When should be the firing time?
public void schedule(String triggerName, String jobName, String group, Date startDate, String timezoneString, String cronExp){
try {
JobDetail jobDetail = new JobDetail(jobName, group, MessageJob.class);
TimeZone timeZone = TimeZone.getTimeZone(timezoneString);
Date startDate = startDate;
Calendar cal1 = Calendar.getInstance();
cal1.setTime(startDate);
cal1.setTimeZone(timeZone);
startDate = cal1.getTime();
CronTrigger cronTrigger = new CronTrigger(triggerName, group, jobName, jobGroup, startDate, null, cronExp, timeZone);
scheduler.start();
} catch (ParseException e) {
System.out.println("ParseException issues " + e.getMessage());
}catch(IllegalArgumentException e){
System.out.println("IllegalArgumentException issues " + e.getMessage());
}
}

If you explicitely set a different timezone in a Quartz cron trigger, then the trigger will fire according to the trigger configuration in the specified time zone. I.e. your cron trigger expresion will be evaluated using the Australia/Melbourne timezone.
To prove this, I created a sample cron trigger with the Australia/Melbourne time zone in QuartzDesk. My local timezone is CET (Central European Time). In the GUI you can clearly see that the trigger's next fire time as returned by Quartz is 2014-12-04 14:00:00 (in the local CET time zone).
Now when you convert this time to the Australia/Melbourne timezone (I use this online converter), I get 2014-12-04 00:00:00 which is the expected trigger time:
As for when your cron expression (0 0/1 * 1/1 * ? *) fires, it fires every minute on every hour (01:00:00, 01:01:00,...) in the Australia/Melbourne timezone. Now considering that Taipei is Australia/Melbourne + 3 hours, then the fire times in your timezone will be 21:01:00, 21:02:00, ...

Related

send Timestamp to firebase

I try to make all date in the fire base at the same time zone for users from all the world.
How I got the same result from this two lines of code , thought I changed the timezone of the date and still the local date give the same timestamp as UTC time zone?
print(Timestamp.fromDate(DateTime.now()).toDate());
print(Timestamp.fromDate(DateTime.now().toUtc()).toDate());
print(Timestamp.fromDate(DateTime.now()).toDate());
print(Timestamp.fromDate(DateTime.now().toUtc()).toDate());
The DateTime type has a DateTime.utc() constructor you can use to create a UTC time:
print(DateTime.now());
print(DateTime.now().toUtc());
print(DateTime.utc(
DateTime.now().year,
DateTime.now().month,
DateTime.now().day,
DateTime.now().hour,
DateTime.now().minute,
DateTime.now().second,
).toUtc());
By default, the DateTime.now() constructor is in the user's local time:
print(DateTime.now().isUtc); // false

Converting the Time format in dateTime from 00:00:00 to 23:59:59

I have converted a Date into DateTime format, and it is returning me the hour format in 00:00:00 but I want it to be in 23:59:59
Date startDate = Date.newInstance(2021,2,1);
This returns the output as 2021-02-01 00:00:00
When I try to convert this to the 23:59:59 hour format by using the below code
DateTime startDateConvertTwo = DateTime.newInstance(startDate, Time.newInstance(23, 59, 59, 0));
It is pushing the date to next day and returning the value of 2021-02-02 07:59:59
I tried to sort this out by changing the values of Time.newInstance by adding it as Time.newInstance(15, 59, 59, 0) by doing which I get the expected result. But is it the right way to achieve what I am trying to do?
Please let me know if there are any other ways.
The returned output of Date startDate = Date.newInstance(2021,2,1); is not 2021-02-01 00:00:00. It's just a date with no information about time, but System.debug() display it as a DateTime, that's why you see 00:00:00.
Try System.debug(String.valueOf(startDate)); to see only the Date part.
DateTime.newInstance(date, time)
Constructs a DateTime from the specified date and time in the local time zone.
As documentation states, the DateTime you get is in your own time zone. Anyway System.debug() shows it in UTC time zone (GMT+0), so if your time zone is GMT-8 you'll see 2021-02-02 07:59:59.
System.debug(String.valueOf(startDateConvertTwo )); will shows the DateTime in your own time zone, so you'll see 2021-02-01 23:59:59.
If you need a DateTime in GMT you could use DateTime.newInstanceGmt(date, time):
DateTime startDateGMT = DateTime.newInstanceGmt(startDate, Time.newInstance(23, 59, 59, 0));
If you cannot use that method, you could add your offset to a DateTime:
public static DateTime toUTC(DateTime value) {
Integer offset = UserInfo.getTimezone().getOffset(value);
return value.addSeconds(offset/1000);
}
You could test it in anonymous console:
Date startDate = Date.newInstance(2021,2,1);
DateTime startDateConvertTwo = DateTime.newInstance(startDate, Time.newInstance(23, 59, 59, 0));
DateTime startDateGMT = DateTime.newInstanceGmt(startDate, Time.newInstance(23, 59, 59, 0));
DateTime startDateGMT2 = toUTC(startDateConvertTwo);
System.debug('startDateConvertTwo: ' + startDateConvertTwo); // startDateConvertTwo: 2021-02-01 22:59:59 // Because I'm at GMT+1
System.debug('String.valueOf(startDateConvertTwo): ' + String.valueOf(startDateConvertTwo)); // String.valueOf(startDateConvertTwo): 2021-02-01 23:59:59
System.debug('startDateGMT: ' + startDateGMT); // startDateGMT: 2021-02-01 23:59:59 // Now it's in UTC
System.debug('String.valueOf(startDateGMT): ' + String.valueOf(startDateGMT)); // String.valueOf(startDateGMT): 2021-02-02 00:59:59 // So in my locale time it's the day after,
System.debug('startDateGMT2: ' + startDateGMT2); // startDateGMT2: 2021-02-01 23:59:59 // Same as startDateGMT
System.debug('String.valueOf(startDateGMT2): ' + String.valueOf(startDateGMT2)); // String.valueOf(startDateGMT2): 2021-02-02 00:59:59
public static DateTime toUTC(DateTime value) {
Integer offset = UserInfo.getTimezone().getOffset(value);
return value.addSeconds(offset/1000);
}
The output of startDateGMT and startDateGMT2 will be the same.
Noteworthy: DateTime fields are stored in GMT. When shown in the standard Salesforce UI, they're converted to the user's timezone.

Working with Date() in Swift and having issues adjusting timezones for storing and reading back in Firestore/Firebase

I am storing dates from a Swift Project in Firestore without any problem. Dates are converted into UTC format and stored in Firestore as a Timestamp. All good.
Then, back on clientside, I can read them back and apply the TimeZone.current and the date/time are adjusted accordingly based on the timezone the user is currently in.
So, as en example, a time originally of:
9:00 pm Melbourne time (which is GMT+10),
shows as 7:00 am if the user is in New York.
Great.
But I have some items that I want to adjust for timezones (as per above) and others I don't.
So say I have two items the same as the above example, but one is an alarm and I want to keep at the time it was originally set for regardless of the new timezone... So still keep it at 9:00 pm.
I have a Bool flag saved in my database to say ignoreTimezone but I'm lost as to how to do this in Swift when reading back the timestamp from Firestore in UTC format and get it back to the original 9:00 pm.
All the Q&A's I've found are all about converting timezones etc. but not really on this example of ignoring one and keeping the date and time set to the timezone they were originally set for.
Thanks in advance for any help and/or suggestions.
Question updated as recommended
I have now incorporated the suggested code. So have a calendar extension:
extension Calendar {
func offsetFromMidnight(for date: Date) -> TimeInterval {
return date.timeIntervalSince(startOfDay(for: date))
}
}
Then I carry out the recommended steps.
Take an offset from midnight, in this case, the current Date():
let offsetSinceMidnight = UInt64(Calendar.current.offsetFromMidnight(for: Date()))
This value is then stored on the server.
I'm currently in Melbourne (Australia), so the date and time item used for testing is July 9 # 2:00pm.
When it is retrieved on the client end in a different timezone, I'm using the recommended code:
//Create a calendar for the target timezone
guard let chicagoTimeZone = TimeZone(identifier: "America/Chicago") else { fatalError() }
var chicagoCalendar = Calendar(identifier: .gregorian)
chicagoCalendar.timeZone = chicagoTimeZone
//Calculate midngiht in the target calendar
let chicagoMidnight = chicagoCalendar.startOfDay(for: Date())
//calculate the same time-of-day in the new timezone
let adjustedChicagoTime = Date(timeInterval: TimeInterval(offsetSinceMidnight), since: chicagoMidnight)
The output is set to the correct time, 2:00pm in Chicago, but because of the differnent dates (Chicago is still July 8th), then the midnight timeinterval is being applied on the wrong date. So I get July 8 # 2:00pm.
I'm assuming I will also need to capture the original date components to apply the offsetSinceMidnight to a date in the newTimeZone that has matching date components??? Or is there a better approach to this?
Date objects store an instant in time, anywhere in the world. They don't capture the idea of a time-of-day regardless of time zone.
To do that I would suggest calculating an offsetFromMidnight value.
Edited to fix return value.
extension Calendar {
func offsetFromMidnight(for date: Date) -> TimeInterval {
return date.timeIntervalSince(startOfDay(for: date))
}
}
You'd call that function in the user's current calendar to get the seconds since midnight in the user's current time zone. Save that to your database. (You could round to a long integer with very little loss of precision.)
I happen to BE in the NYT time zone (EDT) so using that as the destination time zone won't work for me since it won't change anything. Instead, I'll show code to convert from my timezone to GMT:
//Run on user's local machine (in EDT in my case):
let offsetSinceMidnight = UInt64(Calendar.current.offsetFromMidnight(for: Date()))
//Save offset to FireStore
Then if you want that same time of day in a new timezone, you'd use code like this:
//Create a calendar for the target time zone (or the user's local time zone on the destination machine)
guard let gmt = TimeZone(abbreviation: "GMT") else { fatalError() }
var gmtCalendar = Calendar(identifier: .gregorian)
gmtCalendar.timeZone = gmt
//Read time offset from FireStore
let offsetFromNYC = Calendar.current.offsetFromMidnight(for: Date())
//Calculate midnight in target calendar
let gmtMidnight = gmtCalendar.startOfDay(for: Date())
//Calculate the same time-of-day in the GMT time zone
let gmtTimeToday = Date(timeInterval: TimeInterval(offsetSinceMidnight), since: gmtMidnight)
print(gmtTimeToday)
Note that the above will give you the same hours/minutes/seconds as the offsetFromMidnight time.
Edit:
If your goal is to set an alarm to the next future time-of-day in the local time zone, you'd need to add logic to check if the computed date/time is in the past and adjust:
//Change adjustedChicagoTime to a var
var adjustedChicagoTime = Date(timeInterval: TimeInterval(offsetSinceMidnight), since: chicagoMidnight)
//If the alarm time is in the past, add a day to the date.
if adjustedChicagoTime < Date() {
adjustedChicagoTime = Calendar.current.date(byAdding: .day,
value: 1, to: adjustedChicagoTime, wrappingComponents: false)
}
Edit #2:
After a back-and-forth, it sounds like you sometimes want to save a date and time that's independent of time zone, like 9:30 AM on 10 July. If I create that date in EDT, and you view it in Melborne, it's ALWAYS 9:30 AM on 10 July.
Other times, you want to upload and download dates & times that honor time zones.
In order to easily do both, I would suggest saving 2 different string date/time fields to FireStore, one with a time zone, and one without. The one with timezone (or rather offset from GMT) would capture a moment in time around the world, and could be converted to a local time.
The one without time zone would describe a day/month/year/hours/minutes in local time.
You could generate/parse those strings in Swift using date formatters like this:
let baseFormatString = "YYYY-MM-dd'T'HH:mm"
let timeZoneFormatString = baseFormatString + "ZZZ"
let noTimeZoneFormatter = DateFormatter()
noTimeZoneFormatter.dateFormat = baseFormatString
let timeZoneFormatter = DateFormatter()
timeZoneFormatter.dateFormat = timeZoneFormatString
Note that by default a date formatter uses the system's time zone, so the "no time zone formatter" would assume the local time zone. If you use it to convert a date string to a date, it will assume the date is in the local time zone.

How to get zone name that respects daylight saving (e.g. EDT)

I have ZonedDateTime instance, trying to get zone as string (e.g. EST/EDT) like this:
merchantLocalReceiptDateTime.getZone().getDisplayName(TextStyle.SHORT, Locale.getDefault())
For my setup, it returns me EST while in fact I was expecting EDT. Pls advise how to get zone string that correctly reflects daylight saving.
static DateTimeFormatter etFormat = DateTimeFormatter.ofPattern("MM/dd/yyyy 'at' hh:mma 'ET'");
static ZoneId istZoneId = ZoneId.of("Asia/Kolkata");
static ZoneId etZoneId = ZoneId.of("America/New_York");
LocalDateTime currentDateTime = LocalDateTime.now();
ZonedDateTime currentISTime = currentDateTime.atZone(istZoneId);
ZonedDateTime currentETime = currentISTime.withZoneSameInstant(etZoneId); //ET Time
System.out.println(etFormat.format(currentETime));
Ok, I do not like this solution but it is the only one I came up with so far, the only one that works:
So we have preinitialized ZonedDateTime merchantLocalReceiptDateTime (remember, this is threetenbp). We can do this then (is it daylight saving for given time?):
boolean isDaylightSaving = merchantLocalReceiptDateTime.getZone()
.getRules().isDaylightSavings(merchantLocalReceiptDateTime.toInstant());
Then, to get short representation of timezone that respects daylight saving, we can do this (TimeZone is not part of threeten, it is java.util):
TimeZone.getTimeZone(merchantLocalReceiptDateTime.getZone().getId())
.getDisplayName(isDaylightSaving, TimeZone.SHORT)
For New York (assuming device language is English/United States), the above produces EST in winter and EDT right now. For timezones without particular daylight saving names, it can give, for example, "GMT+2", "GMT+3" etc. If language is different, you will likely get those "GMT+-".
//SHORT: CEST
DateTimeFormatter.ofPattern("zzz").format(zonedDateTime)
//SHORT: CET
ZoneId.getDisplayName(TextStyle.SHORT,Locale.ENGLISH)
//LONG: Central European Summer Time
DateTimeFormatter.ofPattern("zzzz").format(zonedDateTime)
//LONG: Central European Time
ZoneId.getDisplayName(TextStyle.LONG,Locale.ENGLISH)
//Use this for converting CET to CEST and vice versa
TimeZone tz = TimeZone.getTimeZone(timeZone.getZone());
tz.getDisplayName(true, TimeZone.SHORT, Locale.ENGLISH));

Is it possible to find data from MySQL by month using JPA and java.time.LocalDate date format?

I creating an application, for that I need to find data by month using JPA and java.time.LocalDate. So, is it possible to retrieve data by month from mysql?
Thanks in advance for help.
First find start and end date of month and use between method of JPA to find data of current month.
LocalDate start = LocalDate.ofEpochDay(System.currentTimeMillis() / (24 * 60 * 60 * 1000) ).withDayOfMonth(1);
LocalDate end = LocalDate.ofEpochDay(System.currentTimeMillis() / (24 * 60 * 60 * 1000) ).plusMonths(1).withDayOfMonth(1).minusDays(1);
In Repository
List<Object> findByCreatedateGreaterThanAndCreatedateLessThan(LocalDate start,LocalDate end);
Its better to use the between keyword, it makes things allot shorter.
List<Object> findByCreatedateBetween(LocalDate start,LocalDate end);
Also if you want to use the LocalDate or LocalDateTime objects with Spring Data you should use the converter class Jsr310JpaConverters or else the documents will be stored as Blobs instead of Dates (which is bad for portability of the database). Please see this tutorial on how to implement the Converter.
https://www.mkyong.com/spring-boot/spring-boot-spring-data-jpa-java-8-date-and-time-jsr310/
tl;dr
YearMonth.now( ZoneId.of( "Pacific/Auckland" ) ) // Get current month for particular time zone.
.atDayOfMonth( 1 ) // Get the first date of that month.
.plusMonths( 1 ) // Get first of next month for Half-Open query.
Details
Assuming your column in MySQL is of DATE type…
LocalDate
The LocalDate class represents a date-only value without time-of-day and without time zone.
Time zone
A time zone is crucial in determining a date. For any given moment, the date varies around the globe by zone. For example, a few minutes after midnight in Paris France is a new day while still “yesterday” in Montréal Québec.
Specify a proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).
ZoneId z = ZoneId.of( "America/Montreal" );
LocalDate today = LocalDate.now( z );
YearMonth
The YearMonth class represents an entire month. Getting the current month requires a time zone as discussed above. Around the beginning/ending of the month, the current moment could be “next” month in Auckland New Zealand while still “previous” month in Kolkata India.
YearMonth currentMonth = YearMonth.now( z ) ;
Get the first date of the month.
LocalDate start = currentMonth.atDayOfMonth( 1 ) ;
Half-Open
Generally best to use the Half-Open [) approach to defining a span of time, where the beginning is inclusive while the ending is exclusive. So defining a month means starting with the first date of the month and running up to, but not including, the first date of the following month.
LocalDate stop = start.plusMonths( 1 ) ;
Query
Do not use the BETWEEN command in SQL as it is fully closed [], both beginning and ending being inclusive. Half-Open uses >= & < logic.
SELECT when FROM tbl
WHERE when >= start
AND when < stop
;
it's also useful
#Query("from PogWorkTime p where p.codePto = :codePto and month(p.dateApply) = :month and year(p.dateApply) = :year")
Iterable<PtoExceptWorkTime> findByCodePtoAndDateApply_MonthAndDateApply_Year(#Param("codePto") String codePto,#Param("month") int month, #Param("year") int year);