Type-safe time calculations in Kotlin, powered by generics.

Overview

Time

JitPack Build Status Coverage Codacy License

This library is made for you if you have ever written something like this:

val duration = 10 * 1000

to represent a duration of 10 seconds(in milliseconds) because most methods in Kotlin/Java take duration parameters in milliseconds.

Usage

Showcase

val tenSeconds = 10.seconds
val fiveMinutes = 5.minutes
val twoHours = 2.hours
val threeDays = 3.days
val tenMinutesFromNow = Calendar.getInstance() + 10.minutes
val tenSecondsInMilliseconds = 10.seconds.inMilliseconds

Basics

The main advantage of the library is that all time units are strongly-typed. So, for example:

val tenMinutes = 10.minutes

In the example above, tenMinutes will be of type Interval<Minute>. There are seven time units available, from nanoseconds to days:

val tenNanoseconds = 10.nanoseconds 
// type is Interval<Nanosecond>
val tenMicroseconds = 10.microseconds 
// type is Interval<Microsecond>
val tenMilliseconds = 10.milliseconds 
// type is Interval<Millisecond>
val tenSeconds = 10.seconds 
// type is Interval<Second>
val tenMinutes = 10.minutes 
// type is Interval<Minute>
val tenHours = 10.hours 
// type is Interval<Hour>
val tenDays = 10.days 
// type is Interval<Day>

Operations

You can perform all basic arithmetic operations on time intervals, even of different units:

val duration = 10.minutes + 15.seconds - 3.minutes + 2.hours // Interval<Minute>
val doubled = duration * 2

val seconds = 10.seconds + 3.minutes // Interval<Second>

You can also use these operations with the Calendar class:

val twoHoursLater = Calendar.getInstance() + 2.hours

Conversions

Time intervals are easily convertible:

val twoMinutesInSeconds = 2.minutes.inSeconds // Interval<Second>
val fourDaysInHours = 4.days.inHours // Interval<Hour>

You can also use the converted() method, although you would rarely need to:

val tenMinutesInSeconds: Interval<Second> = 10.minutes.converted()

Comparison

You can compare different time units as well:

50.seconds < 2.hours // true
120.minutes == 2.hours // true
100.milliseconds > 2.seconds // false
48.hours in 2.days // true

Creating your own time units

If, for some reason, you need to create your own time unit, that's super easy to do:

class Week : TimeUnit {
    // number of seconds in one week
    override val timeIntervalRatio = 604800.0
}

Now you can use it like any other time unit:

val fiveWeeks = Interval<Week>(5)

For the sake of convenience, don't forget to write those handy extensions:

class Week : TimeUnit {
    override val timeIntervalRatio = 604800.0
}

val Number.weeks: Interval<Week>
    get() = Interval(this)

val Interval<TimeUnit>.inWeeks: Interval<Week>
    get() = converted()

Now you can write:

val fiveWeeks = 5.weeks // Interval<Week>

You can also easily convert to weeks:

val valueInWeeks = 14.days.inWeeks // Interval<Week>

Extras

The library includes some handy extensions for some classes:

val now = Calendar.getInstance() 
val sixHoursLater = now + 6.hours
val fourDaysAgo = now - 4.days
val timer = Timer()
timer.schedule(10.seconds) {
    println("This block will be called in 10 seconds")
}

The library also includes extensions for Android's Handler class, this is only available if you compile the "time-android" module.

val handler = Handler()
handler.postDelayed({
    Log.i("TAG", "This will be printed to the Logcat in 2 minutes")
}, 2.minutes)

More extensions will be added to the library in the future.

Conversion safety everywhere

For time-related methods in other third-party libraries in your project, if such methods are frequently used, it's best to write extention functions that let you use the time units in this libary in those methods. This is mostly just one line of code.

If such methods aren't frequently used, you can still benefit from the conversion safety that comes with this library.

An example method in a third-party library that does something after a delay period in milliseconds:

class Person {
    fun doSomething(delayMillis: Long) {
        // method body
    }
}

To call the method above with a value of 5 minutes, one would usually write:

val person = Person()
person.doSomething(5 * 60 * 1000)

The above line can be written in a safer and clearer way using this library:

val person = Person()
person.doSomething(5.minutes.inMilliseconds.longValue)

If the method is frequently used, you can write an extension function:

fun Person.doSomething(delay: Interval<TimeUnit>) {
    doSomething(delay.inMilliseconds.longValue)
}

Now you can write:

val person = Person()
person.doSomething(5.minutes)

Installation

Add the JitPack repository to your build.gradle:

allprojects {
 repositories {
    maven { url "https://jitpack.io" }
    }
}

Add the dependency to your build.gradle:

  • For non-Android projects:
dependencies {
    compile 'com.github.kizitonwose.time:time:<version>'
}
  • For Android projects:
dependencies {
    compile 'com.github.kizitonwose.time:time-android:<version>'
}

Contributing

The goal is for the library to be used wherever possible. If there are extension functions or features you think the library should have, feel free to add them and send a pull request or open an issue. Core Kotlin extensions belong in the "time" module while Android extensions belong in "time-android" module.

Inspiration

Time was inspired by a Swift library of the same name - Time.

The API of Time(Kotlin) has been designed to be as close as possible to Time(Swift) for consistency and because the two languages have many similarities. Check out Time(Swift) if you want a library with the same functionality in Swift.

License

Time is distributed under the MIT license. See LICENSE for details.

Comments
  • Using 3.5.0 (gradle-5.4.1), you must import time lib too, not just time-android

    Using 3.5.0 (gradle-5.4.1), you must import time lib too, not just time-android

    Just updated an older project where I was using this library to Android Gradle Plugin 3.5.0 ( gradle wrapper dist gradle-5.4.1 ). Initially I was just using implementation 'com.github.kizitonwose.time:time-android:1.0.2' as instructed in the readme, and it was working.

    After update, there were many errors ( e.g. extension functions on Int like .seconds were on red - not found ). Weirdly the time:1.0.2 classes somehow aren't in classpath anymore . The workaround solution was to add time:1.0.2 as direct dependency of the project, but it should be checked what did 3.5.0 break.

    I'll give it a shot on fixing and make a PR when I have some free time

    opened by KushtrimPacaj 4
  • Artifacts on bintray

    Artifacts on bintray

    Any chance of the artifacts being uploaded to bintray rather than using jitpack. This is definitely preferred for commercial projects as well as generally being more stable.

    opened by mattmook 2
  • Operator extension functions do not support time intervals longer than Int.MAX_VALUE

    Operator extension functions do not support time intervals longer than Int.MAX_VALUE

    Reproduction steps

    1. Create a time interval for years:
    class Year : TimeUnit {
        override val timeIntervalRatio = 31_556_952.0
    }
    
    val Number.years: Interval<Year>
    	get() = Interval(this)
    
    1. Create a Calendar instance and add 1 year:
    val cal = Calendar.getInstance() + 1.years
    

    Expected behavior

    The calendar instance adds 1 year to the current time.

    Actual behavior

    1 year is not added to the calendar instance.


    If you change the following extensions functions to use timeInMillis instead of converting the long to an int and using Calendar#add it would fix the intended behavior for time intervals over Int.MAX_VALUE:

    operator fun Calendar.plus(other: Interval<TimeUnit>): Calendar = (clone() as Calendar).apply {
        timeInMillis += other.inMilliseconds.longValue
    }
    
    operator fun Calendar.minus(other: Interval<TimeUnit>): Calendar = (clone() as Calendar).apply {
        timeInMillis -= other.inMilliseconds.longValue
    }
    
    opened by jaredrummler 1
  • Add a toString method and ability to get value and units

    Add a toString method and ability to get value and units

    So TimeUnit should have a toString that returns a string like "days" or "minutes" Interval should have a toString that returns a string like "15 seconds" Interval should have properties for the actual value and TimeUnit:

    val a = 15.minutes
    val b = a.value // == 15
    val c = a.unit // == Minute
    val d = a.unit.toString() // == "15 minutes"
    

    This is more for debugging/logging purposes than application output so internationalization is not an issue

    opened by dalewking 0
  • Add support for Java 8 time and date classes

    Add support for Java 8 time and date classes

    Add support for adding intervals to classes like LocalDate. Might want to do it as a separate library and might want to also do it for the 310 backport as well

    opened by dalewking 0
Releases(1.0.4)
Owner
Kizito Nwose
Android and iOS software developer.
Kizito Nwose
Beautifully designed Pokémon Database app for Android based on PokéAPI and powered by Kotlin.

PokéFacts PokéFacts is an open-source Pokémon Database app for Android based on PokéAPI and powered by Kotlin. The app allows users to view Pokémons,

Arjun Mehta 9 Oct 22, 2022
MangaKu App Powered by Kotlin Multiplatform Mobile, Jetpack Compose, and SwiftUI

MangaKu ?? Introduction MangaKu App Powered by Kotlin Multiplatform Mobile, Jetpack Compose, and SwiftUI Module core: data and domain layer iosApp: io

Uwais Alqadri 132 Jan 8, 2023
A discord bot made in Kotlin powered by JDA and Realms.

A discord bot made in Kotlin powered by JDA and Realms.

null 1 Jun 30, 2022
A smart colored time selector. Users can select just free time with a handy colorful range selector.

Colored Time Range Selector A smart colored time range selector. Users can select just free time with a handy colorful range selector. Screen Shots Fe

Ehsan Mehranvari 154 Oct 3, 2022
WorkManager ,One time,Sequential Execution, Periodic time Execution

WokManagerSample WorkManager ,One time,Sequential Execution, Periodic time Execu

Chhote Lal Pal 0 Dec 21, 2021
It is far easier to design a class to be thread-safe than to retrofit it for thread safety later

"It is far easier to design a class to be thread-safe than to retrofit it for thread safety later." (Brian Goetz - Java concurrency: Publisher: Addiso

Nguyễn Trường Thịnh 3 Oct 26, 2022
A highly customizable calendar library for Android, powered by RecyclerView.

CalendarView A highly customizable calendar library for Android, powered by RecyclerView. With this library, your calendar will look however you want

Kizito Nwose 3.4k Jan 3, 2023
:blowfish: An Android & JVM key-value storage powered by Protobuf and Coroutines

PufferDB PufferDB is a ⚡ key-value storage powered by Protocol Buffers (aka Protobuf) and Coroutines. The purpose of this library is to provide an eff

Adriel Café 94 Dec 7, 2022
A libre smart powered comic book reader for Android.

Seeneva A libre smart powered comic book reader for Android. Translation: Русский • • Features • Speech balloons zooming • OCR and TTS • Performance •

Seeneva comic book reader 130 Jan 7, 2023
On-device wake word detection powered by deep learning.

Porcupine Made in Vancouver, Canada by Picovoice Porcupine is a highly-accurate and lightweight wake word engine. It enables building always-listening

Picovoice 2.8k Dec 30, 2022
MyAndroidTools, but powered by Sui

MyAndroidTools 便捷地管理您的 Android 设备 简介 与另一款 MyAndroidTools 一样,本应用使你能够便捷地管理 Android 设备中的应用和组件。但与之不同的是,本应用通过 Sui 来调用高权限 API,所以不会在使用过程中频繁弹出 root 授权的 Toast

null 7 Sep 17, 2022
A pluggable sealed API result type for modeling Retrofit responses.

A pluggable sealed API result type for modeling Retrofit responses.

Slack 645 Dec 19, 2022
Basic app to use different type of observables StateFlow, Flow, SharedFlow, LiveData, State, Channel...

stateflow-flow-sharedflow-livedata Basic app to use different type of observables StateFlow, Flow, SharedFlow, LiveData, State, Channel... StateFlow,

Raheem 5 Dec 21, 2022
A Kotlin Native program to show the time since a date, using Kotlin LibUI

TimeSince A Kotlin Native program to show the time since a date, using Kotlin LibUI Report Bug . Request Feature About The Project TimeSince is a Kotl

Russell Banks 2 May 6, 2022
Utility for developers and QAs what helps minimize time wasting on writing the same data for testing over and over again. Made by Stfalcon

Stfalcon Fixturer A Utility for developers and QAs which helps minimize time wasting on writing the same data for testing over and over again. You can

Stfalcon LLC 31 Nov 29, 2021
A fork of our clean architecture boilerplate, this time using the Android Architecture Components

Android Clean Architecture Components Boilerplate Note: This is a fork of our original Clean Architecture Boilerplate, except in this repo we have swi

Buffer 1.3k Jan 3, 2023
The Superhero app keeps track of the near real-time location of all the volunteers.

Superhero The Superhero app keeps track of the near real-time location of all the volunteers. The app sends requests for emergency tasks to nearby vol

CoronaSafe Network 4 May 3, 2022
Clean MVVM with eliminating the usage of context from view models by introducing hilt for DI and sealed classes for displaying Errors in views using shared flows (one time event), and Stateflow for data

Clean ViewModel with Sealed Classes Following are the purposes of this repo Showing how you can remove the need of context in ViewModels. I. By using

Kashif Mehmood 22 Oct 26, 2022
Add Wheel Date - Time Picker in Android Jetpack Compose.

WheelPickerCompose Add Wheel Date - Time Picker in Android Jetpack Compose. Usage Picker Usage WheelDateTimePicker { snappedDateTime -> } WheelDatePic

Emir Demirli 81 Dec 30, 2022