Comments (7)
Hi Martin, thank you for your report. Will investigate this next week, but looks weird.
from cronos.
And ignore my remarks! Turns out I was constructing my dateTime input object incorrect making it shift 1 hour over.
I was doing
var now = DateTimeOffset.Now;
now = new DateTimeOffset(now.Year, now.Month, now.Day, now.Hour, now.Minute, 0, TimeZoneInfo.Local.BaseUtcOffset);
Instead of
var now = DateTimeOffset.Now;
now = new DateTimeOffset(now.Year, now.Month, now.Day, now.Hour, now.Minute, 0, TimeZoneInfo.Local.GetUtcOffset(now));
from cronos.
Hi, @mw911 . Thank you for your report!
First of all, could you tell us more about your use case? Why did you choose GetNextOccurrence
method overload with inclusive = true
in a iteration process?
Let's consider using method:
DateTimeOffset? GetNextOccurence(DateTimeOffset fromUtc, TimeZoneInfo zone, bool inclusive)
It works with DateTimeOffset in specific time zone. There aren't types in .NET appropriate for local date and time in specific time zone, so we have to use a pair fromUtc
and zone
. In the world NodaTime with ZonedDateTime and LocalDateType types we would implement another method:
ZonedDateTime? GetNextOccurence(ZonedDateTime fromZoned, bool inclusive)
It would accept and return ZonedDateTime
object which represents local date and time in specific time zone. It would be much clearer that the method operates with local time but not utc time. But we don't have such types so we convert fromUtc to fromZoned inside GetNextOccurence
method before we start looking for next occurrence.
In your case we are dealing with transition to summer time. According to Cronos docs:
During the transition to Summer time, the clock is moved forward, for example the next minute after 01:59 AM is 03:00 AM. So any daily Cron expression that should match 02:30 AM, points to an invalid time. It doesn't exist, and can't be mapped to UTC.
Cronos adjusts the next occurrence to the next valid time in these cases.
GetNextOccurence
looks for the first next occurrence after fromUtc satisfying specific cron expression, THEN if found occurrence points to invalid time Cronos ajusts occurrence to the next valid time.
Consider your case in details.
0 2 * * 0
- cron expression "Every Sunday at 02:00 am"
CET - time zone with DST transition forward from 2021-03-28 01:59:59 +1:00 am to 2021-03-28 3:00:00 am +2:00. So [2:00; 3:00) is invalid time.
2021-03-28 00:59 UTC
is 2021-03-28 01:59 +1:00 CET
. Next appropriate occurrence after 2021-03-28 01:59
is 2021-03-28 02:00
. But it's invalid time in CET so we ajusts time to next valid local time: 2021-03-28 03:00 +2:00 CET
2021-03-28 01:00 UTC
is 2021-03-28 03:00 +2:00 CET
(as 2021-03-28 02:00 +1:00 CET
does not exist). Next appropriate occurrence AFTER 2021-03-28 03:00
is 2021-04-04 02:00
(at 02:00 next sunday). So returned value will be 2021-04-04 02:00 +2:00 CET
from cronos.
Hi Andrej
really many thanks for looking into it and coming back to me including such a detailed explanation+questions.
My app (running on a server) executes scheduled tasks. Every minute it uses the current time (truncated to the minute) - let's name it Event time - and compares it with the next occurence of each task - therefore with include=true. It is not an iteration process. These tasks could also use a "simple" schedule which I recently re-wrote based on NodaTime due to the extact same issue I observed with DST (and other problems with my algorithm).
I was able to follow your points and that the behavior I observed is indeed in line with the Cronos docs. I just have thought, that it is strange, that I get the expected result when doing a "forecast" on the minute right before DST but not on DST.
Unfortunately Cronos doesn't support NodaTime ... but now I am thinking of deducting 1 second from the Tick time above and use include=false instead. Not sure if that will work and/or introduces other side effects. I already have ZonedDateTime available for the "simple" schedule and that would return the right time in UTC when I deduct 1 second.
Accordingly, it looks like I have found no error but it could not be solved otherwise without NodaTime. I will check next week and let you know the outcome of my planned change.
Best regards
Martin
from cronos.
that I get the expected result when doing a "forecast" on the minute right before DST but not on DST
The problem is that the 2021-03-28T01:00:00.0000000Z
instant in UTC is ambiguous and can be mapped to the following local time:
2021-03-28 02:00 +1:00 CET
(pre-DST), expected when performing iterations for which you don't want to miss anything.2021-03-28 03:00 +2:00 CET
(DST) is also expected – consider you are starting your problem for the first time exactly at03:00 +2:00 CET
UTC – you'll not expect that it will give you occurrence from the past.
So both behaviours are expected in different conditions, but mutually exclusive – we need to pick one mapping. And in my opinion it's much better to document that any iterations should be performed with inclusive=false
due to this corner case. Is it possible to modify your implementation in this way?
from cronos.
In the meantime it all makes sense and as I said, this was forcing me to re-write the logic for the "simple" schedule using NodaTime.
Due to having that foundation, I was able to change the relevant line (simplified) from
GetNextOccurrence(Date.UtcNow.Truncate(TimeSpan.FromMinutes(1)), timeZone, True)
to (_now is NodaTime.ZonedDateTime truncated to the current minute)
GetNextOccurrence(_now.PlusSeconds(-1).ToDateTimeUtc, timeZone, False)
and it is working fine for both DST cases.
Many thanks for your help with this and I hope that these comments might help others in a similar situation.
Best regards
Martin
from cronos.
@odinserj Sorry to bring this up again, but I think there is actually still an issue here.
As you can see I'm passing a locally formatted DateTimeOffset: 2021-08-15 5:18:00 PM -07:00
.
I explicitly retrieve my current timezone, MST, then I parse the cron (which is 0 * * * *
) and then call GetNextOccurrence
with that timezone and Include true
.
The result is though: 2021-08-15 7:00:00 PM -06:00
.
Which is wrong because it's supposed to 6PM instead of 7PM, and it's reporting -06:00 instead of -07:00.
When I go back in time to like March this year, it does work correctly. It seems that DST isn't regarded when using local times.
from cronos.
Related Issues (20)
- Problem with parsing days of month with comma HOT 2
- Feature Request: Support an array of cron expressions HOT 2
- GetOcccurances from and to inclusive does not work
- GetOcccurances from and to inclusive does not work HOT 1
- invalid value for system.timers.timer HOT 2
- What's the logic behind the unreachable dates? HOT 6
- Shouldn't 0 0 15,L * ? work? HOT 7
- Possible edge condition problem HOT 3
- Support NodaTime
- Cronos.CronFormatException: "Unexpected character '*'." HOT 3
- Feature request: Method for checking if now is a valid occurance HOT 2
- Feature Request: "TryParse" or/and "IsValid" methods HOT 4
- Second weekday of the month
- .Net 6 and .Net8 Support?
- Fortnight how to run a Job every Fortnight , It's every second SAT. or /14 days. HOT 6
- Minor request: Public variables for Hourly / Daily / Minutely HOT 1
- Any way to parse a cron expression and then access its values?
- cronos is missing NuGet package README file HOT 1
- GetPreviousOccurrence
- */15 not firing correctly HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from cronos.