【问题标题】:Improve my Scala : conditional date time parsing改进我的 Scala:条件日期时间解析
【发布时间】:2013-12-06 00:25:20
【问题描述】:
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. 有没有更好的方法来向客户端公开发生什么类型的日期时间匹配,trait -> case 类需要大量输入。
  2. 如何让 case 类隐式转换为时区,我只是在此处使用 case 类进行注释,不想继续输入 .dt
  3. 正则表达式插值代码(我从某处随机获取)似乎很基础,它是否存在于库中,还是我必须将其包含在我的代码中?。
  4. 还有其他建议可以使代码更健壮/更短吗?

【问题讨论】:

  • 这个问题可能更适合codereview.stackexchange.com
  • aww shucks,这种多元化是疯了,不知道存在!嗯,它仍处于测试阶段。

标签: scala idioms


【解决方案1】:

Take may answer with a 一粒盐,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)

回答您的问题

  1. 和 2. 不是真的。 OO 方法是扩展DateTime,但该类是最终的。另一种方法是返回一个元组,调用者可以通过以下方式简单地提取元组:

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

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

  2. 参见上一页

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

    为了使它更健壮,我会更多地使用 JodaTime 的 LocalDate 和 LocalTime 来处理今天/昨天的内容。我还希望删除隐含的 StringContext,因为我觉得这是一个不必要的复杂问题。

    此外,为了更好地使用,您可以将 Context 设为隐式,因此需要声明一次。

我想出的最终代码:

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

结论

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

【讨论】:

    猜你喜欢
    • 2017-08-03
    • 1970-01-01
    • 2014-01-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-04
    • 2015-07-22
    相关资源
    最近更新 更多