改进我的Scala:条件日期时间解析

时间:2013-11-21 13:41:30

标签: scala idioms

object Utility {
    object Time {
        implicit class Regex(sc: StringContext) {
            def r = new util.matching.Regex(sc.parts.mkString, sc.parts.tail.map(_ => "x"): _*)
        }

        case class DTCtxt(val formatter: DateTimeFormatter, tz: DateTimeZone)

        trait BaseRelativeTime { def dt: DateTime }
        case class Today(val dt: DateTime) extends BaseRelativeTime
        case class Yesterday(val dt: DateTime) extends BaseRelativeTime
        case class Absolute(val dt: DateTime) extends BaseRelativeTime

        def parseRelativeDateTime(str: String, dtCtxt: DTCtxt) = {
            println(str)
            val dateTimeNow = DateTime.now()
            val otherDateTimeNow = dateTimeNow.toDateTime(dtCtxt.tz)

            def update_hour(h: String, s: String) =
                if (s == "AM") h.toInt else if(h.toInt == 12) 0 else h.toInt + 12

            str match {
                case r"Today, (\d\d)$h:(\d\d)$m (\w\w)$s" =>
                    Today(otherDateTimeNow.withTime(update_hour(h, s), m.toInt, 0, 0))
                case r"Yesterday, (\d\d)$h:(\d\d)$m (\w\w)$s" =>
                    Yesterday(otherDateTimeNow.minusDays(1).withTime(update_hour(h, s), m.toInt, 0, 0))
                case dt@_ =>
                    Absolute(dtCtxt.formatter.parseDateTime(dt))
            }
        }

        def guardedParseRelativeDateTime(str: String, dtCtxt: DTCtxt) = {
            if(str.isEmpty)
                None
            else
                Some(parseRelativeDateTime(str, dtCtxt))
        }
    }
}
  1. 是否有更好的方式来揭示客户端发生了什么类型的日期时间匹配,特征 - >案例类很多都是打字。
  2. 如何让case类隐式转换为时区,我只是在这里使用case类进行注释,而不想继续输入.dt
  3. 正则表达式插值代码(我从某个地方随机选取),看起来很基础,它是否存在于库中,或者我是否必须将其包含在我的代码中?。
  4. 使代码更强大/更短的任何其他建议?

1 个答案:

答案 0 :(得分:1)

可以用一粒盐,YMMV回答。

小事(一些代码审查)

  1. 案例类不需要val,因为它已经暗示,它们将是公开的:

    case class DTCtxt(formatter: DateTimeFormatter, tz: DateTimeZone)
    case class Today(dt: DateTime) extends BaseRelativeTime
    
  2. 命名的东西:我觉得DTCtxt有点神秘,我更喜欢一个更冗长的名字,例如:DateTimeContext。我们通常也会使用驼峰式方法:def updateHour

  3. DateTime.now可以使用DateTimeZone参数:val dateTimeNow = DateTime.now(dateTimeContext.tz)
  4. 回答您的问题

    1. 和2.不是。面向对象的方法是扩展DateTime,但课程是最终的。另一种方法是返回一个元组,调用者可以通过以下方式提取元组:

      def createDatetime(...): (DateTime, BaseRelativeTime)
      val (dateTime, typ) = createDatetime(...)
      

      我不会说这是一个更好的解决方案,但它有所不同。你可能会发现这更好。我个人喜欢你的案例类封装方法。

    2. 见prev。

    3. 正则表达式代码很好,但我宁愿使用JodaTime的解析功能。例如。模式hh:mm aa与你拥有的模式相匹配 - 如果你剥离今天和昨天。例如:DateTimeFormat.forPattern("hh:mm aa").parseDateTime(timeString).toLocalTime
    4. 为了缩短它,我觉得毫无意义。如果您真的想要简短,那么只需将所有内容放在一行:)。我会努力让它更清楚。

      为了使它更强大,我会使用更多JodaTime的LocalDate和LocalTime作为今天/昨天的东西。我也希望删除隐式StringContext,因为我觉得这是一个不必要的复杂化。

      另外,为了使它更好用,你可以使Context隐含,所以需要声明一次。

    5. 我提出的最终代码:

      case class DateTimeContext(formatter: DateTimeFormatter, tz: DateTimeZone)
      
      sealed trait DateTimeType { def prefix: String }
      case object Today extends DateTimeType { val prefix = "Today, " }
      case object Yesterday extends DateTimeType { val prefix = "Yesterday, " }
      case object Absolute extends DateTimeType { val prefix = "" }
      
      def createDatetime(dateTimeString: String)(implicit dateTimeContext: DateTimeContext): (DateTime, DateTimeType) = {
        val date = DateTime.now(dateTimeContext.tz).toLocalDate
        val TimeFormat = DateTimeFormat.forPattern("hh:mm aa")
      
        def parseTime(timeString: String) = TimeFormat.parseDateTime(timeString).toLocalTime
      
        dateTimeString match {
          case today if today.startsWith(Today.prefix) =>
            val time = parseTime(today.stripPrefix(Today.prefix))
            val dt = date.toDateTime(time, dateTimeContext.tz)
            (dt, Today)
          case yesterday if yesterday.startsWith(Yesterday.prefix) =>
            val time = parseTime(yesterday.stripPrefix(Yesterday.prefix))
            val dt = date.minusDays(1).toDateTime(time, dateTimeContext.tz)
            (dt, Yesterday)
          case _ =>
            (dateTimeContext.formatter.parseDateTime(dateTimeString), Absolute)
        }
      }
      

      致电:

      implicit val dtContext = DateTimeContext(null, DateTimeZone.UTC)
      val str = "Yesterday, 11:56 PM"
      val (dt, typ) = createDatetime(str)
      println(dt) // 2013-11-20T23:56:00.000Z
      println(typ) // Yesterday
      

      <强>结论

      我建议您从这个答案中使用您喜欢的内容。正如我所提到的,我更喜欢案例类封装,只是想展示你可以尝试的不同方法。