Git Product home page Git Product logo

island-time's People

Contributors

brewin avatar erikc5000 avatar renovate[bot] avatar serebit avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

island-time's Issues

Split the core JVM variant up to create a separate Android variant

When trying out the new java.time desugaring support, I discovered that Android doesn't support ZoneRulesProvider at all (they've removed it from the docs entirely), relying on the ICU TimeZone class instead for its TZDB. That class is API 24 and above and unfortunately, not desugared as far as I can tell.

It should be possible to implement an Island Time TimeZoneRulesProvider that uses the android.icu.TimeZone class. Of course, with a minimum API version that's going to be a deal breaker for many right now.

It's unclear if there's any way to make this work with the Android default TZDB on older API versions -- short of typealiasing the Java 8 time classes anyway, which is not a road I'd like to go down.

Creating a time zone rules provider that packages its own TZDB, which can be used on any platform supported by Island Time might be an avenue worth pursuing in the long term, but the threetenabp-extensions will accomplish that for Android at the moment. Just with extra baggage in a world where java.time is desugared. Another option too is creating a derivative of threetenabp/threetenbp with all the non-TZDB essential parts removed.

There is definitely value in providing an option to package a TZDB rather than relying on a potentially outdated default. See recent Brazil time zones woes: https://www.reddit.com/r/androiddev/comments/e00swv/does_anyone_face_brazils_dst_related_issue_by/

Edit: My initial assessment was off. It's possible to get enough information from the available desugared java.time APIs to make everything work. It'll just require doing things a bit different on Android.

Interval construction by "earlier" or "later" durations

When constructing intervals, it would be nice to support a syntax like:

for (date in today until 1.weeks.later) {
    // ...
}

for (date in 1.weeks.earlier until today) {
    // ...
}

It reads a bit nicer than:

for (date in today until today + 1.weeks) {
    // ...
}

for (date in today - 1.weeks until today) {
    // ...
}

The ".earlier" and ".later" would just be syntactic sugar around a duration unit, but at no added expense if implemented using an inline class. We could forego the the sugar and use the durations directly, but it's a little less clear.

for (date in today until 1.weeks) {
    // ...
}

for (date in 1.weeks until today) {
    // ...
}

toComponents() is inconsistent between Duration and duration unit classes

Duration splits into just nanoseconds for the sub-second component. The individual unit clases like IntMilliseconds split into each applicable sub-second unit -- in this case, milliseconds.

Not sure if this is what one would expect. Could allow it to split into "seconds and nanoseconds" in addition to "seconds and milliseconds".

Add nanosecond-precision clock

The current clock implementation is limited to millisecond precision, which is the best you can get with Android or Java 8 anyway. But on Java 9 and iOS/macOS, microsecond resolution is available.

Millisecond resolution may be fine for most and should be a bit faster -- certainly, it'll result in fewer allocations when getting the current time. The default should probably be nanosecond precision where available, but providing the option to use a faster millisecond precision clock would be the best of both worlds.

To support nanosecond precision time on Java 9, we'd want to introduce a PlatformInstant expect class that is implemented by Java's Instant class and wrap Java's Clock. This should keep additional allocations to a minimum. Since we'd be using java.time classes under the hood, this implementation won't work on Android though, so it'll require a new target or project rearrangement of some sort.

Add additional range/interval operators

Some of the following operators could be quite useful additions:

  • range1 union range2
  • range1 intersect range2
  • range1 span range2
  • range1.abuts(range2)
  • range1.encloses(range2)
  • range1.overlaps(range2)
  • range.mapEndpoints(start = { it.startOfWeek }, endInclusive = { it.endOfWeek })
  • range.mapEndpoints { it.startOfWeek } - apply a function to both endpoints
  • range.shiftedBy((-1).days) - specialization of mapEndpoints that maps the start/end by a period or duration
  • range.copy(start = anotherDate)

ZonedDateTimeInterval and OffsetDateTimeInterval pose some challenges since the endpoints may have different zones or offsets. It might make sense to have them return InstantInterval if you try to perform a union or intersection on them, for example.

Issue building for iOS - atomicfu

I have been trying to fix this build error on iOS item and finally narrowed it down to island-time. I added Kotlin atomicfu and made various other attempts to fix it

Extracting dependency: /Users/runner/.konan/cache/clang-llvm-apple-8.0.0-darwin-macos.tar.gz into /Users/runner/.konan/dependencies
e: Could not find "atomicfu-cinterop-interop" in [/Users/runner/runners/2.262.1/work/ReimaginedLampMobileApps/ReimaginedLampMobileApps, /Users/runner/.konan/klib, /Users/runner/.konan/kotlin-native-macos-1.3.71/klib/common, /Users/runner/.konan/kotlin-native-macos-1.3.71/klib/platform/ios_x64].

Is there a sample project I could look at?

Here is a branch and build for repro

Thank you for making this library, hope to use it

Consider converting some of the current inline classes to non-inline

Current inline classes that are candidates for being converted to regular classes:

  • Year
  • YearMonth
  • UtcOffset
  • TimeZone

While having Year and YearMonth as inline classes might reduce allocations in some situations, it creates issues with construction, validation, and Java/ObjC interop. I see these classes being more valuable once a base class is introduced that allows mixed precision dates and ranges to be represented (ie. 2004/2005-02-08 or 2018-04/2019). When used in that context, they'll be boxed anyway. But having Year as a thin wrapper around an Int that exposes appropriate operations can be nice.

val year = Year(2020)
val leapYear = year.isLeap

I'm leaning in favor of regular classes, but would like to hear other's thoughts.

As for UtcOffset and TimeZone, they could probably just use some form of caching to reduce allocations instead of being inline classes.

Edit: TimeZone is no longer an inline class since it made consistent fixed zone behavior across platforms easier.

Overflow safety in duration unit classes

For the most part, Island Time detects and throws an exception on overflow, like java.time does. The unit classes are a bit inconsistent in that they aren't overflow safe by default.

Consider IntHours:

val totalHours = Int.MAX.hours + 1.hours // overflow
val minutes = Int.MAX.hours.inMinutes // overflow
val minutes2 = Int.MAX.hours.inMinutesExact() // exception

Internally, we have plusExact and minusExact infix functions to do overflow safe math. The question is whether or not these should be the default and instead, require a plusWithOverflow, minusWithOverflow, or inMinutesWithOverflow. I'm leaning "yes", but curious to hear if others have an opinion on this.

On native, it seems like LLVM's UBSan could be used to detect overflow during debug as a possible alternative, though not sure if enabling it is possible with Kotlin Native. Doesn't help with JVM though, obviously.

Handle conflicting fields when resolving parsed objects

Right now, if a DateTime parser provides both DAY_OF_MONTH and DAY_OF_YEAR, it'll just take the day of month value first assuming it has a year and month. But the day of year value may conflict or otherwise be indicative of a poorly defined custom parser.

This sort of behavior needs to looked at across all date-time primitives and may require more sophisticated resolution behavior.

Construction patterns

The manner in which objects are constructed isn't entirely consistent at the moment. The most "Kotlin" approach is a bit of a question mark though and certainly worthy of discussion.

We have classes like Duration and Period, which do construction like so:

val duration = durationOf(5.seconds, 5.nanoseconds)
val period = periodOf(2.years, 3.days)

This reads nicely and feels natural enough with the "of", though such syntax tends to be used with list arguments.

Then we have classes like Date or DateTime that use regular constructors or constructor functions that start with capitals.

val date = Date(2019, Month.May, 5)
val dateTime = DateTime(2019, 5, 5, 13, 0)

Then we have Time, which uses invoke() on the companion object so that it can do some object pooling prior to actual construction, making it a bit weird. Companion invokes all need to go, but what is the right construction method? timeOf()? But then should all of the date-time representations use a similar style? What makes for the best syntax here?

Increase supported year range

It should be possible to increase the supported year range to match java.time. I capped it 1-9999 initially just to keep things simple.

This will require more tests to cover the expanded range and the ISO-8601 parsers should be modified to support "expanded" year formats.

Consider exposing only Long duration unit classes

Right now, each duration unit has a separate Long and Int class generated for it. For example:

val longNanoseconds: LongNanoseconds = 8L.nanoseconds
val intNanoseconds: IntNanoseconds = 8.nanoseconds

While it can be quite useful having both representations and it allows for choosing the appropriate backing primitive for different situations, it does result in an explosion of signatures in the public API. And it would be nice to just see Nanoseconds as the name.

We could continue to use the Int representations to optimize internally, but stop exposing them publicly. It would come at the cost of some efficiency, but it's definitely something to consider.

Application hangs when calling now()

I'm using the latest version of the library (0.6.3). When I'm trying to obtain a current date with the Date.now() application hangs when running it on the iOS Simulator. Is it a known issue?
I also tried Instant.now(), and DateTime.now(), and all of them hang the app.

Parsing AM/PM

Thanks for this useful library! I'm trying to parse a string with AM/PM, but amPm() doesn't seem to have any effect.

val parser = dateTimeParser {
    year(4)
    +'-'
    monthNumber(2)
    +'-'
    dayOfMonth(2)
    +' '
    hourOfDay(2)
    +':'
    minuteOfHour(2)
    +' '
    amPm()
}

val hour = "2020-07-14 03:56 PM".toDateTime(parser).hour.toString()
println(hour)

I expected hour to be 15, but it's 3. Is this a bug or am I missing something?

Case sensitivity in parsing

All parsing done by DateTimeParsers is currently case-sensitive, which is alright for strict ISO-8601 parsing, but could be an issue when dealing with custom formats.

We could add a global setting on DateTimeParserSettings that allows any parser to be used in a case-sensitive or insensitive mode.

We could also add the ability to the change the case sensitivity of parsing within a given block. java.time allows that.

val parser = dateTimeParser {
    caseInsensitive {
        +" hours"
        caseSensitive { +" of day" }
    }
}

Consider making ranges/intervals sealed classes

Empty and unbounded might be better handled with sealed classes. That would make it possible to do away with using MIN and MAX sentinels, which create some headaches currently -- and in the case of ZonedDateTime, Android java.time desugaring can't support properly (#57).

Add support for writing to custom formats

It should be possible to define a custom format similar to how a custom parser can be defined. Something like:

val customFormat = dateTimeFormat {
    monthNumber()
    +'/'
    dayOfMonth()
}

val date = Date(2019, 10, 28)
val string = date.toString(customFormat)

For the initial implementation, we can avoid adding support anything locale-specific. Locale will open up another can of worms.

Implementing this will probably require inserting an interface into the date-time primitives -- something akin to TemporalAccessor in java.time, but Period and Duration should also implement it since we include parser support for them. This interface should provide access to the available date-time fields on the object.

interface Temporal {
    fun get(field: DateTimeField): Long
}

Introducing a TemporalQuery-like interface for access to non-Long fields may also be necessary.

Ultimately, I'm envisioning the abstractions added here will also tie in with and enable parsing of arbitrary ISO-compliant strings.

val temporal = genericIsoParser.parseAny(text)

if (temporal is Year) {
    // ..
} else if (temporal is Date) {
    // ..
}

This will be useful for working with intervals that have mixed-precision end points, like "2018/2019-05-01".

Obviously, these are more advanced use cases though, so the focus should initially be on what's necessary to support custom formatting.

Convert Instant to non-inline class

Instant is an inline class right now that piggybacks on Duration and gives it a different interface. While that's convenient, it brings with it all the usual inline class limitations. This should be converted to a regular class that recycles Duration code like in java.time.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.