项目作者: mlopes

项目描述 :
Date and time types and instances
高级语言: Scala
项目地址: git://github.com/mlopes/wen.git
创建时间: 2019-04-18T21:09:58Z
项目社区:https://github.com/mlopes/wen

开源协议:Apache License 2.0

下载


Build Status
Coverage Status
Codacy Badge
License
Maven Central

wen

‘Wen considered the nature of time and understood that the universe is, instant by instant, recreated anew. Therefore, he understood, there is in truth no past, only a memory of the past. Blink your eyes, and the world you see next did not exist when you closed them. Therefore, he said, the only appropriate state of the mind is surprise. The only appropriate state of the heart is joy. The sky you see now, you have never seen before. The perfect moment is now. Be glad of it.’

― Terry Pratchett, Thief of Time

Date and time types and instances

Getting Started

Wen is available for Scala 2.12. You can add wen to your sbt project by adding the following to
your build.sbt:

  1. libraryDependencies += "dev.mlopes" %% "wen" % "1.0.0-M1"
  2. libraryDependencies += "dev.mlopes" %% "wen-cats" % "1.0.0-M1" // For cats instances
  3. libraryDependencies += "dev.mlopes" %% "wen-circe" % "1.0.0-M1" // For circe encoders and decoders

What is Wen?

Wen provides types to safely represent months, weekdays, years, epoch, hours, minutes,
seconds and milliseconds, as well as instances of the Order, Eq and Show cats type classes.

Should cats ever support the Enum and Bounded type classes, and we should implement those as
well, for the relevant types.

What Wen isn’t?

Wen does not aim for date/time related functionality like the one provided by the
java.time. Its purpose is to provide stateless representations for date/time data types.

Types

Wen provides types to represent date/time components, as well as types for full time and date representations, and auxiliary refined types for numeric representation of date/time components.

Date/Time Components

Day

Constructors
Day(day: NumericDay): Day
Day.fromInt(day: Int): Option[Day]
Instances
Order[Day]
Eq[Day]
Show[Day]

Usage

  1. import wen.types._
  2. import eu.timepit.refined.{W, refineMV}
  3. import eu.timepit.refined.numeric.Interval
  4. val day = Day.fromInt(31)
  5. // day: Option[wen.types.Day] = Some(Day(31))
  6. val notDay = Day.fromInt(32)
  7. // notDay: Option[wen.types.Day] = None
  8. // You need to use refineV when refining non-literal values
  9. val refinedDay = Day(refineMV[Interval.Closed[W.`1`.T, W.`31`.T]](22))
  10. // refinedDay: wen.types.Day = Day(22)
  11. import eu.timepit.refined.auto._
  12. // This works because we add the type annotation to `autoRefinedDay`
  13. // so Scala infers that we're using the constructor
  14. // Day(numericDay: NumericDay): Day
  15. // refined.auto provides the necessary implicit conversion from Int.
  16. val autoRefinedDay: Day = Day(25)
  17. // autoRefinedDay: wen.types.Day = Day(25)

Because instances of cats’s Eq, Order and Show are available, we can also do the following:

  1. import cats.implicits._ // for cats syntax
  2. import wen.implicits._ // for wen's instances
  3. refinedDay.show
  4. // res0: String = 22
  5. autoRefinedDay >= refinedDay
  6. // res1: Boolean = true
  7. refinedDay =!= autoRefinedDay
  8. // res2: Boolean = true

Month

Constructors
January
February
March
April
May
June
July
August
September
October
November
December
Month(numericMonth: NumericMonth): Month
Month.fromInt(month: Int): Option[Month]
Month.fromString(month: String): Option[Month]
Instances
Order[Month]
Eq[Month]
Show[Month]

Members

  1. Month.asInt: Int

Returns the ordinal number of a Month, starting at 1 for January and ending in 12 for December.

Usage

  1. import wen.types._
  2. import eu.timepit.refined.{W, refineMV}
  3. import eu.timepit.refined.numeric.Interval
  4. val month: Month = December
  5. // month: wen.types.Month = December
  6. val monthFromInt = Month.fromInt(7)
  7. // monthFromInt: Option[wen.types.Month] = Some(July)
  8. val monthFromString = Month.fromString("July")
  9. // monthFromString: Option[wen.types.Month] = Some(July)
  10. val notMonth = Month.fromInt(24)
  11. // notMonth: Option[wen.types.Month] = None
  12. val notMonthFromString = Month.fromString("Grune")
  13. // notMonthFromString: Option[wen.types.Month] = None
  14. // You need to use refineV when refining non-literal values
  15. val refinedMonth = Month(refineMV[Interval.Closed[W.`1`.T, W.`12`.T]](4))
  16. // refinedMonth: wen.types.Month = April
  17. val monthInt = June.asInt
  18. // monthInt: Int = 6
  19. import eu.timepit.refined.auto._
  20. val autoRefinedMonth: Month = Month(8)
  21. // autoRefinedMonth: wen.types.Month = August

Because instances of cats’s Eq, Order and Show are available, we can also do the following:

  1. import cats.implicits._ // for cats syntax
  2. import wen.implicits._ // for wen's instances
  3. refinedMonth.show
  4. // res0: String = April
  5. refinedMonth > autoRefinedMonth
  6. // res1: Boolean = false
  7. refinedMonth === autoRefinedMonth
  8. // res2: Boolean = false
  9. // Note that we have to specify the type Month so that Scala doesn't infer the type as July
  10. (July : Month).show
  11. // res3: String = July

Year

Constructors
Year(year: NumericYear): Year
Year(year: NumericYear, epoch: Epoch): Year
Year.fromInt(year: Int): Option[Year]
Year.fromIntWithEpoch(year: Int, epoch: Epoch): Option[Year]
Instances
Order[Year]
Eq[Year]
Show[Year]

Usage

  1. import wen.types._
  2. import eu.timepit.refined.{W, refineMV}
  3. import eu.timepit.refined.numeric.{Interval, Positive}
  4. val adYear = Year.fromIntWithEpoch(2019, AD)
  5. // adYear: Option[wen.types.Year] = Some(Year(2019,AD))
  6. val yearWithDefaultEpoch1 = Year.fromInt(2012)
  7. // yearWithDefaultEpoch1: Option[wen.types.Year] = Some(Year(2012,AD))
  8. val bcYear = Year.fromIntWithEpoch(19, BC)
  9. // bcYear: Option[wen.types.Year] = Some(Year(19,BC))
  10. val notYear = Year.fromIntWithEpoch(-21, AD)
  11. // notYear: Option[wen.types.Year] = None
  12. // You need to use refineV when refining non-literal values
  13. val refinedYear = Year(refineMV[Positive](2019), AD)
  14. // refinedYear: wen.types.Year = Year(2019,AD)
  15. val yearWithDefaultEpoch = Year(refineMV[Positive](2011))
  16. // yearWithDefaultEpoch: wen.types.Year = Year(2011,AD)
  17. import eu.timepit.refined.auto._
  18. val autoRefinedYear: Year = Year(2000, AD)
  19. // autoRefinedYear: wen.types.Year = Year(2000,AD)

Because instances of cats’s Eq, Order and Show are available, we can also do the following:

  1. import cats.implicits._ // for cats syntax
  2. import wen.implicits._ // for wen's instances
  3. refinedYear.show
  4. // res0: String = 2019
  5. yearWithDefaultEpoch.show
  6. // res1: String = 2011
  7. refinedYear <= refinedYear
  8. // res2: Boolean = true
  9. refinedYear === autoRefinedYear
  10. // res3: Boolean = false

Epoch

Constructors
BC
AD
Epoch.fromString(epoch: String)
Instances
Order[Epoch]
Eq[Epoch]
Show[Epoch]
  1. val epochFromString = Epoch.fromString("AD")
  2. // epochFromString: Option[wen.types.Epoch] = Some(AD)
  3. val notEpochFromString = Epoch.fromString("ACDC")
  4. // notEpochFromString: Option[wen.types.Epoch] = None

WeekDay

Constructors
Sunday
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
WeekDay.fromString(weekDay: String): Option[WeekDay]
Instances
Order[WeekDay]
Eq[WeekDay]
Show[WeekDay]

The provided Order instance starts on Sunday and ends on Saturday.

Because instances of cats’s Eq, Order and Show are available, we can do the following:

Usage

  1. import cats.implicits._ // for cats syntax
  2. import wen.implicits._ // for wen's instances
  3. val oneDay: WeekDay = Tuesday
  4. // oneDay: wen.types.WeekDay = Tuesday
  5. val otherDay: WeekDay = Friday
  6. // otherDay: wen.types.WeekDay = Friday
  7. val yetAnotherDay: WeekDay = WeekDay.fromString("Saturday")
  8. // yetAnotherDay: Option[wen.types.WeekDay] = Some(Saturday)
  9. val notAnotherDay: WeekDay = WeekDay.fromString("Caturday")
  10. // notAnotherDay: Option[wen.types.WeekDay] = None
  11. otherDay < oneDay
  12. // res0: Boolean = false
  13. otherDay === oneDay
  14. // res1: Boolean = false
  15. otherDay.show
  16. // res2: String = Friday
  17. // Note that we have to specify the type WeekDay so that Scala doesn't infer the type as Saturday
  18. (Saturday: WeekDay).show
  19. // res3: String = Saturday

There’s also an Order[WeekDay] instance starting on Monday, but it requires the user
to explicitly import it and make it implicit. Note that if you import the default Order
instance for weekday, it will conflict with this one and the compiler won’t be able to infer
which one to use.

Usage

  1. import cats.implicits._
  2. implicit val orderInstance = wen.instances.WeekDayInstances.mondayFirstWeekDayOrderInstance
  3. orderInstance: cats.Order[wen.types.WeekDay] = wen.instances.WeekDayInstances$$anon$1@7da2d02d
  4. import wen.types._
  5. val oneDay: WeekDay = Sunday
  6. // oneDay: wen.types.WeekDay = Sunday
  7. val otherDay: WeekDay = Monday
  8. // otherDay: wen.types.WeekDay = Monday
  9. otherDay < oneDay
  10. // res0: Boolean = true

Hour

Constructors
Hour(hour: NumericHour): Hour
Hour.fromInt(hour: Int): Option[Hour]
Instances
Order[Hour]
Eq[Hour]
Show[Hour]

Usage

  1. import wen.types._
  2. import eu.timepit.refined.{W, refineMV}
  3. import eu.timepit.refined.numeric.{Interval, Positive}
  4. val hour = Hour.fromInt(23)
  5. // hour: Option[wen.types.Hour] = Some(Hour(23))
  6. val notHour = Hour.fromInt(25)
  7. // notHour: Option[wen.types.Hour] = None
  8. // You need to use refineV when refining non-literal values
  9. val refinedHour = Hour(refineMV[Interval.Closed[W.`0`.T, W.`23`.T]](10))
  10. // refinedHour: wen.types.Hour = Hour(10)
  11. import eu.timepit.refined.auto._
  12. val autoRefinedHour: Hour = Hour(12)
  13. // autoRefinedHour: wen.types.Hour = Hour(12)

Because instances of cats’s Eq, Order and Show are available, we can also do the following:

  1. import cats.implicits._ // for cats syntax
  2. import wen.implicits._ // for wen's instances
  3. refinedHour.show
  4. // res0: String = 10
  5. refinedHour > autoRefinedHour
  6. // res1: Boolean = false
  7. autoRefinedHour === autoRefinedHour
  8. // res2: Boolean = true

Minute

Constructors
Minute(minute: NumericMinute): Minute
Minute.fromInt(minute: Int): Option[Minute]
Instances
Order[Minute]
Eq[Minute]
Show[Minute]

Usage

  1. import wen.types._
  2. import eu.timepit.refined.{W, refineMV}
  3. import eu.timepit.refined.numeric.{Interval, Positive}
  4. val minute = Minute.fromInt(0)
  5. // minute: Option[wen.types.Minute] = Some(Minute(0))
  6. val notMinute = Minute.fromInt(-12)
  7. // notMinute: Option[wen.types.Minute] = None
  8. // You need to use refineV when refining non-literal values
  9. val refinedMinute: Minute = Minute(refineMV[Interval.Closed[W.`0`.T, W.`59`.T]](15))
  10. // refinedMinute: wen.types.Minute = Minute(15)
  11. import eu.timepit.refined.auto._
  12. val autoRefinedMinute: Minute = Minute(45)
  13. // autoRefinedMinute: wen.types.Minute = Minute(45)

Because instances of cats’s Eq, Order and Show are available, we can also do the following:

  1. import cats.implicits._ // for cats syntax
  2. import wen.implicits._ // for wen's instances
  3. autoRefinedMinute.show
  4. // res0: String = 45
  5. autoRefinedMinute > refinedMinute
  6. // res1: Boolean = true
  7. autoRefinedMinute =!= refinedMinute
  8. // res2: Boolean = true

Second

Constructors
Second(second: NumericSecond): Second
Second.fromInt(second: Int): Option[Second]
Instances
Order[Second]
Eq[Second]
Show[Second]

Usage

  1. import wen.types._
  2. import eu.timepit.refined.{W, refineMV}
  3. import eu.timepit.refined.numeric.{Interval, Positive}
  4. val second = Second.fromInt(42)
  5. // second: Option[wen.types.Second] = Some(Second(42))
  6. val notSecond = Second.fromInt(591)
  7. // notSecond: Option[wen.types.Second] = None
  8. // You need to use refineV when refining non-literal values
  9. val refinedSecond = Second(refineMV[Interval.Closed[W.`0`.T, W.`59`.T]](20))
  10. // refinedSecond: wen.types.Second = Second(20)
  11. import eu.timepit.refined.auto._
  12. val autoRefinedSecond: Second = Second(12)
  13. // autoRefinedSecond: wen.types.Second = Second(12)

Because instances of cats’s Eq, Order and Show are available, we can also do the following:

  1. import cats.implicits._ // for cats syntax
  2. import wen.implicits._ // for wen's instances
  3. refinedSecond.show
  4. // res0: String = Some(20)
  5. refinedSecond > autoRefinedSecond
  6. // res1: Boolean = true
  7. refinedSecond === autoRefinedSecond
  8. // res2: Boolean = false

Millisecond

Constructors
Millisecond(millisecond: NumericMillisecond): Millisecond
Millisecond.fromInt(millisecond: Int): Option[Millisecond]
Instances
Order[Millisecond]
Eq[Millisecond]
Show[Millisecond]

Usage

  1. import wen.types._
  2. import eu.timepit.refined.{W, refineMV}
  3. import eu.timepit.refined.numeric.{Interval, Positive}
  4. val millisecond = Millisecond.fromInt(456)
  5. // millisecond: Option[wen.types.Millisecond] = Some(Millisecond(456))
  6. val notMillisecond = Millisecond.fromInt(-1)
  7. // notMillisecond: Option[wen.types.Millisecond] = None
  8. // You need to use refineV when refining non-literal values
  9. val refinedMillisecond = Millisecond(refineMV[Interval.Closed[W.`0`.T,
  10. W.`999`.T]](999))
  11. // refinedMillisecond: wen.types.Millisecond = Millisecond(999)
  12. import eu.timepit.refined.auto._
  13. val autoRefinedMillisecond: Millisecond = Millisecond(999)
  14. // autoRefinedMillisecond: wen.types.Millisecond = Millisecond(999)

Because instances of cats’s Eq, Order and Show are available, we can also do the following:

  1. import cats.implicits._ // for cats syntax
  2. import wen.implicits._ // for wen's instances
  3. refinedMillisecond.show
  4. // res0: String = 999
  5. refinedMillisecond >= autoRefinedMillisecond
  6. // res1: Boolean = true
  7. refinedMillisecond === autoRefinedMillisecond
  8. // res2: Boolean = true

Full Representations

Time

Constructors
Time(hour: Hour, minute: Minute, second: Second, millisecond: Millisecond): Time
Time(hour: Hour, minute: Minute, second: Second): Time
Time(hour: Hour, minute: Minute): Time
Time(hour: Hour): Time
Time(time: LocalTime): Time
Instances
Order[Time]
Eq[Time]
Show[Time]

Values for the properties that are not specified, will default to 0.

Usage

  1. import wen.types._
  2. import eu.timepit.refined.auto._
  3. import wen.datetime._
  4. val time1 = Time(Hour(7), Minute(5), Second(10), Millisecond(200))
  5. // time1: wen.datetime.Time = Time(Hour(7),Minute(5),Second(10),Millisecond(200))
  6. val time2 = Time(Hour(7), Minute(5), Second(10))
  7. // time2: wen.datetime.Time = Time(Hour(7),Minute(5),Second(10),Millisecond(0))
  8. val time3 = Time(Hour(7), Minute(5))
  9. // time3: wen.datetime.Time = Time(Hour(7),Minute(5),Second(0),Millisecond(0))
  10. val time4 = Time(Hour(7))
  11. // time4: wen.datetime.Time = Time(Hour(7),Minute(0),Second(0),Millisecond(0))
  12. import java.time.LocalTime
  13. val time5 = Time(LocalTime.now)
  14. // time5: wen.datetime.Time = Time(Hour(7),Minute(2),Second(48),Millisecond(159))

Because instances of cats’s Eq, Order and Show are available, we can also do the following:

  1. import cats.implicits._ // for cats syntax
  2. import wen.implicits._ // for wen's instances
  3. time1.show
  4. // res0: String = 07:05:10.200
  5. time3.show
  6. // res1: String = 07:05:00.0
  7. time1 > time3
  8. // res2: Boolean = true
  9. time2 =!= time4
  10. // res3: Boolean = true

To create a Time from non-refined values, you can do the following:

  1. import wen.types._
  2. import wen.datetime._
  3. val optionTime = for {
  4. hour <- Hour.fromInt(12)
  5. minute <- Minute.fromInt(15)
  6. second <- Second.fromInt(59)
  7. millisecond <- Millisecond.fromInt(908)
  8. } yield Time(hour, minute, second, millisecond)
  9. // optionTime: Option[wen.datetime.Time] = Some(Time(Hour(12),Minute(15),Second(59),Millisecond(908)))

ZoneTime

Constructors
ZoneTime(time: Time, offset: Offset): ZoneTime
ZoneTime(offsetTime: OffsetTime): ZoneTime
Instances
Order[ZoneTime]
Eq[ZoneTime]
Show[ZoneTime]
Offset
Constructors
Offset(offsetType: OffsetType, hour: Hour, minute: Minute): Offset
Offset(zoneOffset: ZoneOffset): Offset

Members

  1. UTC: Offset = Offset([UTCPlus](#OffsetType), Hour(0), Minute(0))

Because instances of cats’s Eq, Order and Show are available, we can also do the following:

  1. import wen.datetime._
  2. import wen.implicits._
  3. import cats.implicits._
  4. import wen.types.
  5. val offset1 = Offset.UTC
  6. // offset1: wen.datetime.Offset = Offset(UTCPlus,Hour(0),Minute(0))
  7. val offset2 = Offset(Offset.UTCMinus, Hour.fromInt(5).get, Minute.fromInt(45).get)
  8. // offset2: wen.datetime.Offset = Offset(UTCMinus,Hour(5),Minute(45))
  9. val offset3 = Offset(Offset.UTCPlus, Hour.fromInt(12).get, Minute.fromInt(20).get)
  10. // offset3: wen.datetime.Offset = Offset(UTCPlus,Hour(12),Minute(20))
  11. offset1 > offset2
  12. // res0: Boolean = true
  13. offset3 > offset2
  14. // res1: Boolean = true
  15. offset2 > offset3
  16. // res2: Boolean = false
  17. offset1 === offset2
  18. // res3: Boolean = false
  19. offset1 =!= offset3
  20. // res4: Boolean = true
  21. offset1.show
  22. // res5: String = +00:00
  23. offset2.show
  24. // res6: String = -05:45
  25. offset3.show
  26. // res7: String = +12:20

A Show instance in ISO format is also available:

  1. import wen.types._
  2. import cats.implicits._
  3. import wen.datetime._
  4. import wen.instances.iso.isoOffsetShowInstance
  5. val offset1 = Offset.UTC
  6. // offset1: wen.datetime.Offset = Offset(UTCPlus,Hour(0),Minute(0))
  7. val offset2 = Offset(Offset.UTCMinus, Hour.fromInt(5).get, Minute.fromInt(45).get)
  8. // offset2: wen.datetime.Offset = Offset(UTCMinus,Hour(5),Minute(45))
  9. val offset3 = Offset(Offset.UTCPlus, Hour.fromInt(12).get, Minute.fromInt(20).get)
  10. // offset3: wen.datetime.Offset = Offset(UTCPlus,Hour(12),Minute(20))
  11. offset1.show
  12. // res0: String = Z
  13. offset2.show
  14. // res1: String = -05:45
  15. offset3.show
  16. // res2: String = +12:20
OffsetType
Constructors
UTCMinus
UTCPlus

Usage

  1. import wen.types._
  2. import eu.timepit.refined.auto._
  3. import wen.datetime._
  4. val time1 = Time(Hour(10), Minute(11), Second(12), Millisecond(13))
  5. // time1: wen.datetime.Time = Time(Hour(10),Minute(11),Second(12),Millisecond(13))
  6. val zoneTime1 = ZoneTime(time1, Offset.UTC)
  7. // zoneTime1: wen.datetime.ZoneTime = ZoneTime(Time(Hour(10),Minute(11),Second(12),Millisecond(13)),Offset(UTCPlus,Hour(0),Minute(0)))
  8. val offset1 = Offset(Offset.UTCPlus, Hour(1), Minute(0))
  9. // offset1: wen.datetime.Offset = Offset(UTCPlus,Hour(1),Minute(0))
  10. val offset2 = Offset(Offset.UTCMinus, Hour(1), Minute(0))
  11. // offset2: wen.datetime.Offset = Offset(UTCMinus,Hour(1),Minute(0))
  12. val zoneTime2 = ZoneTime(time1, offset1)
  13. // zoneTime2: wen.datetime.ZoneTime = ZoneTime(Time(Hour(10),Minute(11),Second(12),Millisecond(13)),Offset(UTCPlus,Hour(1),Minute(0)))
  14. val zoneTime3 = ZoneTime(time1, offset2)
  15. // zoneTime3: wen.datetime.ZoneTime = ZoneTime(Time(Hour(10),Minute(11),Second(12),Millisecond(13)),Offset(UTCMinus,Hour(1),Minute(0)))
  16. val time2 = Time(Hour(9), Minute(11), Second(12), Millisecond(13))
  17. time2: wen.datetime.Time = Time(Hour(9),Minute(11),Second(12),Millisecond(13))
  18. val zoneTime4 = ZoneTime(time2, offset1)
  19. // zoneTime4: wen.datetime.ZoneTime = ZoneTime(Time(Hour(9),Minute(11),Second(12),Millisecond(13)),Offset(UTCPlus,Hour(1),Minute(0)))
  20. import java.time.ZoneOffset
  21. val offset3 = Offset(ZoneOffset.MIN)
  22. // offset3: wen.datetime.Offset = Offset(UTCMinus,Hour(18),Minute(0))
  23. import java.time.OffsetTime
  24. val zoneTime5 = ZoneTime(OffsetTime.now)
  25. // zoneTime5: wen.datetime.ZoneTime = ZoneTime(Time(Hour(21),Minute(33),Second(10),Millisecond(1)),Offset(UTCPlus,Hour(1),Minute(0)))

Because instances of cats’s Eq, Order and Show are available, we can also do the following:

  1. import cats.implicits._ // for cats syntax
  2. import wen.implicits._ // for wen's instances
  3. zoneTime1.show
  4. // res0: String = 10:11:12.13 +00:00
  5. zoneTime2.show
  6. // res1: String = 10:11:12.13 +01:00
  7. zoneTime4.show
  8. // res2: String = 09:11:12.13 +01:00
  9. zoneTime1 < zoneTime2
  10. // res3: Boolean = true
  11. zoneTime1 === zoneTime4
  12. // res4: Boolean = true

Date

Constructors
Date(localDate: LocalDate): Date
Date.safe(day: Day, month: Month, year: Year): Option[Date]
Date.unsafe(day: Day, month: Month, year: Year): Date
Instances
Order[Date]
Eq[Date]
Show[Date]

The constructor Date.safe(day: Day, month: Month, year: Year): Option[Date] only allows the creation of valid dates, and will return None for invalid dates. The unsafe constructor Date.unsafe(day: Day, month: Month, year: Year): Date allows for creating invalid date combinations such as 30 February 2019.

Dates created from java.time.LocalDate are unsafe, asjava.time.LocalDateallow for invalid dates in the BC epoch. See [issue #19](https://github.com/mlopes/wen/issues/19) for details of why. For all AD, and non leap year BC dates, date creation should yield valid dates only. This is a problem withjava.time.LocalDate`, if you wish to avoid this you’ll need to use one of the other safe constructors.

Usage

  1. import wen.types._
  2. import eu.timepit.refined.auto._
  3. import wen.datetime._
  4. val date = Date.safe(Day(12), Month(8), Year(2016, AD))
  5. // date: Option[wen.datetime.Date] = Some(Date(Day(12),August,Year(2016,AD)))
  6. val notDate = Date.safe((31), September, Year(2000, AD))
  7. // notDate: Option[wen.datetime.Date] = None
  8. val unsafeDate = Date.unsafe(Day(31), August, Year(2019, AD))
  9. // unsafeDate: wen.datetime.Date = Date(Day(31),August,Year(2019,AD))
  10. // This creates an invalid date
  11. val unsafeNotDate = Date.unsafe(Day(31), February, Year(2018, AD))
  12. // unsafeNotDate: wen.datetime.Date = Date(Day(31),February,Year(2018,AD))
  13. import java.time.LocalDate
  14. val date2 = Date(LocalDate.now)
  15. // date2: wen.datetime.Date = Date(Day(2),May,Year(2019,AD))

Because instances of cats’s Eq, Order and Show are available, we can also do the following:

  1. import cats.implicits._ // for cats syntax
  2. import wen.implicits._ // for wen's instances
  3. unsafeDate.show
  4. // res0: String = 31 August 2019
  5. val unsafeDate1 = Date.unsafe(Day(31), August, Year(2018, AD))
  6. // unsafeDate1: wen.datetime.Date = Date(Day(31),August,Year(2018,AD))
  7. unsafeDate < unsafeDate1
  8. // res1: Boolean = false
  9. unsafeDate === unsafeDate1
  10. // res1: Boolean = false

DateTime

Constructors
DateTime(date: Date, time: Time): DateTime
DateTime(localDateTime: LocalDateTime): DateTime
Instances
Order[DateTime]
Eq[DateTime]
Show[DateTime]

Usage

  1. import wen.types._
  2. import eu.timepit.refined.auto._
  3. import wen.datetime._
  4. val date1 = Date.unsafe(Day(12), Month(8), Year(2016, AD))
  5. // date1: wen.datetime.Date = Date(Day(12),August,Year(2016,AD))
  6. val date2 = Date.unsafe(Day(22), Month(8), Year(1982, AD))
  7. // date2: wen.datetime.Date = Date(Day(22),August,Year(1982,AD))
  8. val time1 = Time(Hour(7), Minute(5))
  9. // time1: wen.datetime.Time = Time(Hour(7),Minute(5),Second(0),Millisecond(0))
  10. val time2 = Time(Hour(20), Minute(30))
  11. // time2: wen.datetime.Time = Time(Hour(20),Minute(30),Second(0),Millisecond(0))
  12. val dateTime1 = DateTime(date1, time1)
  13. // dateTime1: wen.datetime.DateTime = DateTime(Date(Day(12),August,Year(2016,AD)),Time(Hour(7),Minute(5),Second(0),Millisecond(0)))
  14. val dateTime2 = DateTime(date2, time2)
  15. // dateTime2: wen.datetime.DateTime = DateTime(Date(Day(22),August,Year(1982,AD)),Time(Hour(20),Minute(30),Second(0),Millisecond(0)))
  16. val dateTime3 = DateTime(date1, time2)
  17. // dateTime3: wen.datetime.DateTime = DateTime(Date(Day(12),August,Year(2016,AD)),Time(Hour(20),Minute(30),Second(0),Millisecond(0)))
  18. import java.time.LocalDateTime
  19. val dateTime4 = DateTime(LocalDateTime.now)
  20. // dateTime4: wen.datetime.DateTime = DateTime(Date(Day(2),May,Year(2019,AD)),Time(Hour(20),Minute(40),Second(16),Millisecond(612)))

Because instances of cats’s Eq, Order and Show are available, we can also do the following:

  1. import cats.implicits._ // for cats syntax
  2. import wen.implicits._ // for wen's instances
  3. dateTime1.show
  4. // res0: String = 12 August 2016 07:05:00.0
  5. dateTime1 > dateTime2
  6. // res1: Boolean = true
  7. dateTime3 > dateTime1
  8. // res2: Boolean = true
  9. dateTime1 =!= dateTime2
  10. // res3: Boolean = true

ZoneDateTime

Constructors
ZoneDateTime(date: Date, zoneTime: ZoneTime): ZoneDateTime
ZoneDateTime(offsetDateTime: OffsetDateTime): ZoneDateTime
ZoneDateTime(instant: Instant): ZoneDateTime
Instances
Order[ZoneDateTime]
Eq[ZoneDateTime]
Show[ZoneDateTime]

Usage

  1. import wen.types._
  2. import eu.timepit.refined.auto._
  3. import wen.datetime._
  4. val date1 = Date.unsafe(Day(12), Month(8), Year(2016, AD))
  5. // date1: wen.datetime.Date = Date(Day(12),August,Year(2016,AD))
  6. val time1 = ZoneTime(Time(Hour(7), Minute(5)), Offset.UTC)
  7. // time1: wen.datetime.ZoneTime = ZoneTime(Time(Hour(7),Minute(5),Second(0),Millisecond(0)),Offset(UTCPlus,Hour(0),Minute(0)))
  8. val time2 = ZoneTime(Time(Hour(7), Minute(5)), Offset(Offset.UTCMinus, Hour(1), Minute(0)))
  9. // time2: wen.datetime.ZoneTime = ZoneTime(Time(Hour(7),Minute(5),Second(0),Millisecond(0)),Offset(UTCMinus,Hour(1),Minute(0)))
  10. val time3 = ZoneTime(Time(Hour(8), Minute(5)), Offset(Offset.UTCMinus, Hour(1), Minute(0)))
  11. // time3: wen.datetime.ZoneTime = ZoneTime(Time(Hour(8),Minute(5),Second(0),Millisecond(0)),Offset(UTCMinus,Hour(1),Minute(0)))
  12. val zoneDateTime1 = ZoneDateTime(date1, time1)
  13. // zoneDateTime1: wen.datetime.ZoneDateTime = ZoneDateTime(Date(Day(12),August,Year(2016,AD)),ZoneTime(Time(Hour(7),Minute(5),Second(0),Millisecond(0)),Offset(UTCPlus,Hour(0),Minute(0))))
  14. val zoneDateTime2 = ZoneDateTime(date1, time2)
  15. // zoneDateTime2: wen.datetime.ZoneDateTime = ZoneDateTime(Date(Day(12),August,Year(2016,AD)),ZoneTime(Time(Hour(7),Minute(5),Second(0),Millisecond(0)),Offset(UTCMinus,Hour(1),Minute(0))))
  16. val zoneDateTime3 = ZoneDateTime(date1, time3)
  17. // zoneDateTime3: wen.datetime.ZoneDateTime = ZoneDateTime(Date(Day(12),August,Year(2016,AD)),ZoneTime(Time(Hour(8),Minute(5),Second(0),Millisecond(0)),Offset(UTCMinus,Hour(1),Minute(0))))
  18. import java.time.OffsetDateTime
  19. import java.time.Instant
  20. val zoneDateTime4 = ZoneDateTime(OffsetDateTime.now)
  21. // zoneDateTime4: wen.datetime.ZoneDateTime = ZoneDateTime(Date(Day(2),May,Year(2019,AD)),ZoneTime(Time(Hour(22),Minute(44),Second(34),Millisecond(833)),Offset(UTCPlus,Hour(1),Minute(0))))
  22. val zoneDateTime5 = ZoneDateTime(Instant.now)
  23. // zoneDateTime5: wen.datetime.ZoneDateTime = ZoneDateTime(Date(Day(2),May,Year(2019,AD)),ZoneTime(Time(Hour(21),Minute(45),Second(7),Millisecond(704)),Offset(UTCPlus,Hour(0),Minute(0))))

Because instances of cats’s Eq, Order and Show are available, we can also do the following:

  1. import cats.implicits._ // for cats syntax
  2. import wen.implicits._ // for wen's instances
  3. zoneDateTime1.show
  4. // res0: String = 12 August 2016 07:05:00.0 +00:00
  5. scala> zoneDateTime2.show
  6. // res1: String = 12 August 2016 07:05:00.0 -01:00
  7. scala> zoneDateTime3.show
  8. // res2: String = 12 August 2016 08:05:00.0 -01:00
  9. zoneDateTime1 > zoneDateTime2
  10. // res3: Boolean = true
  11. zoneDateTime1 === zoneDateTime3
  12. // res4: Boolean = true

Numeric types

Numeric types use refined for type safe representation of date/time components as integers.
These types are available under the wen.types.NumericTypes namespace.

NumericDay

  1. type NumericDay = Int Refined Interval.Closed[W.`1`.T, W.`31`.T]

NumericMonth

  1. type NumericMonth = Int Refined Interval.Closed[W.`1`.T, W.`12`.T]

NumericYear

  1. type NumericYear = Int Refined Positive

NumericHour

  1. type NumericHour = Int Refined Interval.Closed[W.`0`.T, W.`23`.T]

NumericMinute

  1. type NumericMinute = Int Refined Interval.Closed[W.`0`.T, W.`59`.T]

NumericSecond

  1. type NumericSecond = Int Refined Interval.Closed[W.`0`.T, W.`59`.T]

NumericMillisecond

  1. type NumericMillisecond = Int Refined Interval.Closed[W.`0`.T, W.`999`.T]

Refinement Helpers

Refinement helpers are made available under the wen.refine namespace.

Their purpose is to make it easier to refine integer values into
NumericTypes, without the user having to know about
un-specialised refinement types.

The following refinement helper functions are available:

functions
def refineHour(hour: Int): Either[String, NumericHour]
def refineMinute(minute: Int): Either[String, NumericMinute]
def refineSecond(second: Int): Either[String, NumericSecond]
def refineMilliSecond(millisecond: Int): Either[String, NumericMillisecond]
def refineYear(year: Int): Either[String, NumericYear]
def refineMonth(month: Int): Either[String, NumericMonth]
def refineDay(day: Int): Either[String, NumericDay]

Usage

  1. def time(hour: Int, minute: Int, second: Int): Either[String, Time] =
  2. for {
  3. h <- refineHour(hour)
  4. m <- refineMinute(minute)
  5. s <- refineSecond(second)
  6. ms <- refineMilliSecond(millisecond)
  7. } yield new Time(Hour(h), Minute(m), Second(s), Millisecond(ms))

ISO-8601 instances

ISO-8601 instances are made available under the wen.instances.iso namespace.

ISO Instances
Show[Date]
Show[Time]
Show[ZoneTime]
Show[DateTime]
Show[ZoneDateTime]

ISO show instances are an alternative to the default ones provided in wen.implicits.
Unlike the default instances which return the dates/times in human readable format,
ISO instances return the dates in ISO-8601 format.

See here for the wikipedia entry on ISO-8601.

Note that when using the ISO instances you can’t import the instances under wen.implicits
or wen.instances otherwise the compiler won’t be able to infer which instances to use for
Show.

Usage

  1. import cats.implicits._
  2. import wen.instances.iso._
  3. import wen.datetime._
  4. import wen.types._
  5. import eu.timepit.refined.auto._
  6. val date1 = Date.unsafe(Day(25), July, Year(1975, AD))
  7. // date1: wen.datetime.Date = Date(Day(25),July,Year(1975,AD))
  8. val date2 = Date.unsafe(Day(1), January, Year(2131, BC))
  9. // date2: wen.datetime.Date = Date(Day(1),January,Year(2131,BC))
  10. date1.show
  11. // res0: String = 1975-07-25
  12. scala> date2.show
  13. // res1: String = -2130-01-01
  14. val date3 = Date.unsafe(Day(2), March, Year(1, BC))
  15. // date3: wen.datetime.Date = Date(Day(2),March,Year(1,BC))
  16. val time = Time(Hour(8), Minute(53), Second(23), Millisecond(900))
  17. // time: wen.datetime.Time = Time(Hour(8),Minute(53),Second(23),Millisecond(900))
  18. val dateTime1 = DateTime(date1, time)
  19. // dateTime1: wen.datetime.DateTime = DateTime(Date(Day(25),July,Year(1975,AD)),Time(Hour(8),Minute(53),Second(23),Millisecond(900)))
  20. val dateTime2 = DateTime(date2, time)
  21. // dateTime2: wen.datetime.DateTime = DateTime(Date(Day(1),January,Year(2131,BC)),Time(Hour(8),Minute(53),Second(23),Millisecond(900)))
  22. val dateTime3 = DateTime(date3, time)
  23. // dateTime3: wen.datetime.DateTime = DateTime(Date(Day(2),March,Year(1,BC)),Time(Hour(8),Minute(53),Second(23),Millisecond(900)))
  24. dateTime1.show
  25. // res2: String = 1975-07-25T08:53:23
  26. dateTime2.show
  27. // res3: String = -2130-01-01T08:53:23
  28. dateTime3.show
  29. // res4: String = 0000-03-02T08:53:23
  30. val zoneTime1 = ZoneTime(Time(Hour(8), Minute(15), Second(2), Millisecond(33)),
  31. Offset.UTC)
  32. // zoneTime1: wen.datetime.ZoneTime = ZoneTime(Time(Hour(8),Minute(15),Second(2),Millisecond(33)),Offset(UTCPlus,Hour(0),Minute(0)))
  33. val zoneTime2 = ZoneTime(Time(Hour(10), Minute(31), Second(23), Millisecond(606)),
  34. Offset(Offset.UTCMinus, Hour(1), Minute(0)))
  35. // zoneTime2: wen.datetime.ZoneTime = ZoneTime(Time(Hour(10),Minute(31),Second(23),Millisecond(606)),Offset(UTCMinus,Hour(1),Minute(0)))
  36. val zoneTime3 = ZoneTime(Time(Hour(7), Minute(53), Second(23), Millisecond(900)),
  37. Offset(Offset.UTCPlus, Hour(0), Minute(30)))
  38. // zoneTime3: wen.datetime.ZoneTime = ZoneTime(Time(Hour(7),Minute(53),Second(23),Millisecond(900)),Offset(UTCPlus,Hour(0),Minute(30)))
  39. zoneTime1.show
  40. // res5: String = 08:15:02Z
  41. zoneTime2.show
  42. // res6: String = 10:31:23-01:00
  43. zoneTime3.show
  44. // res7: String = 07:53:23+00:30
  45. val zoneTime1 = ZoneTime(time, Offset.UTC)
  46. // zoneTime1: wen.datetime.ZoneTime = ZoneTime(Time(Hour(8),Minute(53),Second(23),Millisecond(900)),Offset(UTCPlus,Hour(0),Minute(0)))
  47. val zoneTime2 = ZoneTime(time, Offset(Offset.UTCMinus, Hour(1), Minute(0)))
  48. // zoneTime2: wen.datetime.ZoneTime = ZoneTime(Time(Hour(8),Minute(53),Second(23),Millisecond(900)),Offset(UTCMinus,Hour(1),Minute(0)))
  49. val zoneTime3 = ZoneTime(time, Offset(Offset.UTCPlus, Hour(2), Minute(45)))
  50. // zoneTime3: wen.datetime.ZoneTime = ZoneTime(Time(Hour(8),Minute(53),Second(23),Millisecond(900)),Offset(UTCPlus,Hour(2),Minute(45)))
  51. val zoneDateTime1 = ZoneDateTime(date1, zoneTime1)
  52. // zoneDateTime1: wen.datetime.ZoneDateTime = ZoneDateTime(Date(Day(25),July,Year(1975,AD)),ZoneTime(Time(Hour(8),Minute(53),Second(23),Millisecond(900)),Offset(UTCPlus,Hour(0),Minute(0))))
  53. val zoneDateTime2 = ZoneDateTime(date2, zoneTime2)
  54. // zoneDateTime2: wen.datetime.ZoneDateTime = ZoneDateTime(Date(Day(1),January,Year(2131,BC)),ZoneTime(Time(Hour(8),Minute(53),Second(23),Millisecond(900)),Offset(UTCMinus,Hour(1),Minute(0))))
  55. val zoneDateTime3 = ZoneDateTime(date3, zoneTime3)
  56. // zoneDateTime3: wen.datetime.ZoneDateTime = ZoneDateTime(Date(Day(2),March,Year(1,BC)),ZoneTime(Time(Hour(8),Minute(53),Second(23),Millisecond(900)),Offset(UTCPlus,Hour(2),Minute(45))))
  57. zoneDateTime1.show
  58. // res9: String = 1975-07-25T08:53:23Z
  59. zoneDateTime2.show
  60. // res10: String = -2130-01-01T08:53:23-01:00
  61. zoneDateTime3.show
  62. // res11: String = 0000-03-02T08:53:23+02:45

Circe Instances

Circe ISO-8601 encoders and decoders are provided for Date, Time, DateTime, ZoneTime, Offset, and ZoneDateTime.
Circe encoders and decoders are also provided for Day, WeekDay, Month, Year, Epoch, Hour, Minute, Second, and Millisecond.