-
Notifications
You must be signed in to change notification settings - Fork 180
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
JodaTime support month offsets are incorrect and cannot existing data with March 30 dates #37
Comments
@Freaky-namuH can you provide your code snippet? I want to know more details. (I remember I took into account for it in the codes.) |
I've create a test project that highlight the issue using version 0.5.1.1. To create the data: create table datetest(id serial, a_date date);
insert into datetest(a_date) values('2014-03-30');
select * from datetest; Run the
https://docs.google.com/file/d/0B-OQSZyNiKpIM1ppbTE1blFhbXM/edit When you run it you'll see
I rewrote the type conversion using the hibernate joda time project as a base (https://github.com/JodaOrg/joda-time-hibernate/tree/master/src/main/java/org/joda/time/contrib/hibernate) and it works ok. There are some unit test failures that I don't understand (specifically an '-' operator test). Here are the test results I get
This is the final class I came up with package com.github.tminglei.slickpg
import scala.slick.driver.PostgresDriver
import org.joda.time._
import org.joda.time.format.DateTimeFormat
import java.sql.{Timestamp, Time, Date}
import scala.slick.lifted.Column
import org.postgresql.util.PGInterval
trait PgDateSupportJoda extends date.PgDateExtensions with date.PgDateJavaTypes with utils.PgCommonJdbcTypes {
driver: PostgresDriver =>
type DATE = LocalDate
type TIME = LocalTime
type TIMESTAMP = LocalDateTime
type INTERVAL = Period
type TIMESTAMP_TZ = DateTime
trait DateTimeImplicits {
val tzDateTimeFormatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ssZ")
implicit val jodaDateTypeMapper = new DateJdbcType(sqlDate2jodaDate, jodaDate2sqlDate)
implicit val jodaTimeTypeMapper = new TimeJdbcType(sqlTime2jodaTime, jodaTime2sqlTime)
implicit val jodaDateTimeTypeMapper = new TimestampJdbcType(sqlTimestamp2jodaDateTime, jodaDateTime2sqlTimestamp)
implicit val jodaPeriodTypeMapper = new GenericJdbcType[Period]("interval", pgIntervalStr2jodaPeriod, hasLiteralForm = false)
implicit val timestampTZTypeMapper = new GenericJdbcType[DateTime]("timestamptz",
DateTime.parse(_, tzDateTimeFormatter), _.toString(tzDateTimeFormatter), hasLiteralForm = false)
///
implicit def dateColumnExtensionMethods(c: Column[LocalDate]) = new DateColumnExtensionMethods(c)
implicit def dateOptColumnExtensionMethods(c: Column[Option[LocalDate]]) = new DateColumnExtensionMethods(c)
implicit def timeColumnExtensionMethods(c: Column[LocalTime]) = new TimeColumnExtensionMethods(c)
implicit def timeOptColumnExtensionMethods(c: Column[Option[LocalTime]]) = new TimeColumnExtensionMethods(c)
implicit def timestampColumnExtensionMethods(c: Column[LocalDateTime]) = new TimestampColumnExtensionMethods(c)
implicit def timestampOptColumnExtensionMethods(c: Column[Option[LocalDateTime]]) = new TimestampColumnExtensionMethods(c)
implicit def intervalColumnExtensionMethods(c: Column[Period]) = new IntervalColumnExtensionMethods(c)
implicit def intervalOptColumnExtensionMethods(c: Column[Option[Period]]) = new IntervalColumnExtensionMethods(c)
implicit def timestampTZColumnExtensionMethods(c: Column[DateTime]) = new TimestampTZColumnExtensionMethods(c)
implicit def timestampTZOptColumnExtensionMethods(c: Column[Option[DateTime]]) = new TimestampTZColumnExtensionMethods(c)
}
//--------------------------------------------------------------------
/// sql.Date <-> joda LocalDate
private def sqlDate2jodaDate(date: Date): LocalDate = {
new LocalDate(date)
}
private def jodaDate2sqlDate(date: LocalDate): Date = {
new Date(date.toDateTimeAtStartOfDay().toDate().getTime())
}
/// sql.Time <-> joda LocalTime
private def sqlTime2jodaTime(time: Time): LocalTime = {
new LocalTime(time, DateTimeZone.UTC)
}
private def jodaTime2sqlTime(time: LocalTime): Time = {
new Time(time.getMillisOfDay)
}
/// sql.Timestamp <-> joda LocalDateTime
private def sqlTimestamp2jodaDateTime(ts: Timestamp): LocalDateTime = {
new LocalDateTime(ts)
}
private def jodaDateTime2sqlTimestamp(dt: LocalDateTime): Timestamp = {
new Timestamp(dt.toDateTime.toDate.getTime)
}
/// pg interval string <-> joda Duration
private def pgIntervalStr2jodaPeriod(intervalStr: String): Period = {
val pgInterval = new PGInterval(intervalStr)
val seconds = Math.floor(pgInterval.getSeconds).asInstanceOf[Int]
val millis = ((pgInterval.getSeconds - seconds) * 1000).asInstanceOf[Int]
new Period(
pgInterval.getYears,
pgInterval.getMonths,
0, // weeks
pgInterval.getDays,
pgInterval.getHours,
pgInterval.getMinutes,
seconds, millis
)
}
}
I hope this helps. |
Well, I see. I've ever submitted a fix change for this problem to But your way is better, can you send me a pull request? Thanks for your nice help! |
Hi @Freaky-namuH I just published a new version of Pls update libraryDependencies += "com.github.tminglei" % "slick-pg_2.10" % "0.5.1.2"
libraryDependencies += "com.github.tminglei" % "slick-pg_joda-time_2.10" % "0.5.1.2" |
Months in java.util.Calendar are '0' based where as in joda-time months are '1' based.
http://docs.oracle.com/javase/7/docs/api/java/util/Calendar.html#set(int, int, int, int, int, int)
http://joda-time.sourceforge.net/apidocs/org/joda/time/LocalDate.html#LocalDate(int, int, int)
This can be seen by reading a row that has an existing March 30th (2014-03-30) date in it, i.e. not one that has been inserted using the joda-time mapper.
It fails with:
For example, the mapping from a calendar to LocalDate is incorrect
https://github.com/tminglei/slick-pg/blob/master/addons/joda-time/src/main/scala/com/github/tminglei/slickpg/PgDateSupportJoda.scala#L55 as it does not add '1' to the MONTH.
The opposite is also true. https://github.com/tminglei/slick-pg/blob/master/addons/joda-time/src/main/scala/com/github/tminglei/slickpg/PgDateSupportJoda.scala#L55 Does not subtract '1' to the month.
The text was updated successfully, but these errors were encountered: