Closed filogic closed 9 months ago
Thanks for the extensive change request! We encounter the same problem within Simacan and would like to see a solution as well. I think the proposed approach is the cleanest solution but I do also think that most implementations will not be able to support it out of the box.
So, if we continue with this change I think we should add examples for Java, C#, JavaScript, Python as the most popular programming languages on how to deal with this, e.g. how to get some runtime object from the string.
I agree. Maybe the alternative solution is therefore the best solution ? Let's discuss in the working council
I played around with it a bit and could create a Scala version that deals with recurring code. It is not completely foul proof or generic yet, but it shows that it is not too hard to make it work. It can easily be translated to Java since it relies on the java std library.
// Class that **might** contain a recurring date time.
class RecurringDateTime(offsetDateTime: OffsetDateTime, duration: Option[Duration]) {
// check whether it is just a date time or actually recurring
def isRecurring: Boolean =
duration.isDefined
def toOffsetDateTime: OffsetDateTime =
offsetDateTime
// the Nth time slot in the recurring date time. Just repeat the duration N times.
def toOffsetDateTimeAfterIterations(iteration: Int): OffsetDateTime = {
val dur = duration.getOrElse(Duration.ZERO)
var last = offsetDateTime
(0 to iteration).foreach(_ => last = last.plus(dur))
last
}
}
object RecurringDateTime {
// Parse a recurring date time by using the Duration and OffsetDateTime parsers of Java itself.
def parse(string: String): RecurringDateTime = {
val isRecurring = string.startsWith("R")
if (isRecurring) {
// split the time and duration parts
val dateTimePlusDuration = string.dropWhile(char => char != '/').tail
val indexOfSlash = dateTimePlusDuration.indexOf("/")
val (timePart, durationPart) = dateTimePlusDuration.splitAt(indexOfSlash)
val time = OffsetDateTime.parse(timePart)
val duration = Duration.parse(durationPart.tail)
new RecurringDateTime(time, Some(duration))
} else {
new RecurringDateTime(OffsetDateTime.parse(string), None)
}
}
}
We discussed using some existing specification, but I forget which one it was. Do you have anything you could link @filogic?
Might have been this one: https://developers.google.com/calendar/api/concepts/events-calendars#recurrence_rule
My proposal would be to use the Google Calendar API specification and make the following additions:
recurrence
field to all objects that currently have a startTime
and endTime
. The recurrence follows the specification as described on the Google Calendar API spec. recurrence may not be present if startTime
and endTime
are not present.startTime
and endTime
as times without dates, but that would break the current behavior. So I think OTM5 should enforce that there always is a first startTime
and endTime
.duration
(also according to the Google Calendar API & ISO 8601 spec), that may only be present if startTime
and endTime
are absent. To make this more explicit we could add a timeFormat
field that is either dateTime
or duration
. If not filled it will default to dateTime
since that is the behavior from OTM5.5 and older. TODO: check whether there exist standard open source libraries (Java, .NET, JavaScript, Python) that implement the Google API spec so that it is easy to adopt.
I did a bit of digging and found the following blog post. It mentions a few libraries that implement the recurring specification
There are more options per ecosystem, but here are a few examples:
So I think we can embed this is in OTM5 specification.
This is now part of OTM5.6 so can be closed.
Type of request
Is your feature request related to a problem? The Dutch government intends to disseminate information regarding restrictions on public road usage or regional limitations through the use of OpenTripModel. Some of this information has a clear start- and end date while other restrictions are recurring (e.g. weekly markets, school zones, etc ... ).
One of the primary reasons why one would like to specify the start dates of restrictions as recurring dates and times is for the sake of flexibility and efficiency. By allowing for recurring dates and times, it is possible to define restrictions that repeat on a regular basis without the need to manually specify each occurrence individually. This saves time and effort, and allows for more efficient management of road usage restrictions.
For example, imagine a road that needs to be closed to traffic every weekday from 7:00 am to 9:00 am to allow for construction work. Instead of manually specifying the start and end dates for each weekday, it is much more efficient to specify a recurring date and time for the start of the restriction, such as "every weekday at 7:00 am." This way, the restriction can be automatically applied without the need for manual intervention.
Another reason why one would like to specify the start dates of restrictions as recurring dates and times is for the sake of clarity and consistency. By using a standardized format such as ISO 8601, it is possible to clearly define when a restriction begins and ends in a way that is easily understood by both humans and machines.
For example, imagine a road that is closed to traffic every other weekend to allow for a local street fair. Instead of using a non-standard format such as "closed on the second and fourth Saturdays of each month," it is much clearer and more consistent to use a recurring date and time format such as "closed every other Saturday from 8:00 am to 6:00 pm," which conforms to ISO 8601.
In addition, using a standardized format for recurring dates and times makes it easier to integrate this data with other systems and applications that may rely on this information, such as navigation systems or traffic management software. This can help to improve overall traffic flow and reduce congestion by providing accurate and consistent information about road usage restrictions.
Describe the solution you'd like The original version of the ISO 8601 standard, which was published in 1988, did not include support for recurring dates and time intervals, but it did not have a version that explicitly excluded it. The original standard focused on the representation of specific dates and times, and included a comprehensive set of formatting rules for representing dates and times in a way that is unambiguous and universally understood.
Support for recurring dates and time intervals was added in later revisions of the ISO 8601 standard, including the most recent version published in 2019. This extension allows the representation of recurring dates and times in a standardized way, making it easier to exchange and process this type of information across different systems and platforms.
The most recent version is called "ISO 8601:2019 - Representation of dates and times" and it includes provisions for recurring dates and times. The ISO 8601 standard provides several ways to represent recurring moments, including:
ISO 8601 is widely used and recognized in various industries and applications, including computer systems, international trade, and legal documentation.
In JSON, recurring date can be described as followed:
This ISO 8601 representation consists of the following components:
Describe alternatives you've considered Programming languages like C# and JAVA have default (de)serialisation mechanisms build-in. Normally, an ISO-8601 date is parsed to a System.DateTime (C#) or java.time (JAVA) object. These classes do not support recurring dates and timesout of the box.
This means that developers should implement custom (de)serialisation methods that are able to handle the formats described in this change request correctly. An alternative solution would be to add a new property to the timeWindowConstrant called "recurringTime", like depicted below:
A timeWindowConstraint is only valid when either "startTime" or "recurringTime" is set.
In C#, "recurringTime" can be deserialised to
RecurringDate
class from theNodaTime.Extensions
namespace. In JAVA, developers may consider usingjava.time.TemporalAdjuster
interface.