如何识别日期时间格式?

时间:2018-04-02 08:39:33

标签: java scala date datetime

Datetime对象以两种不同的格式进入我的程序:unix时间戳和yyyy-MM-dd HH:mm:ss.S。例如,15208776002018-04-23 11:12:00.0。我需要从这些对象中提取一年和一个月,自动识别格式。

这是从year中提取yyyy-MM-dd HH:mm:ss.S的功能:

  def getYear(datetimeString: Any): Int = {
    var year = 2017
    if (!datetimeString.toString.isEmpty) {
      val dateFormat = "yyyy-MM-dd HH:mm:ss.S"
      val dtf = java.time.format.DateTimeFormatter.ofPattern(dateFormat)
      val d = java.time.LocalDate.parse(datetimeString.toString, dtf)
      year = d.getYear
    }
    year
  } 

这与unix时间戳的功能相同:

  def getYear(timestamp: Any): Int = {
    var year = 2017
    if (!timestamp.toString.isEmpty)
    {
      year = new DateTime(timestamp.toString.toLong).getYear
    }
    year
  }

如何将它们合并到一个函数中,以便我的程序可以灵活运行并适用于这两种格式?

4 个答案:

答案 0 :(得分:1)

您可以使用java.time.format.DateTimeFormatterBuilder构建带有可选部分的格式化程序,其中每个可选部分都是opener = urllib.request.URLopener() opener.addheader('User-Agent', 'whatever') opener.retrieve(manga_url, manga_name) ,可以解析其中一种格式。

我在Java中发布代码,因为我不是Scala开发人员,但应该很难适应它。

首先为日期/时间模式制作格式化程序:

DateTimeFormatter

然后你创建另一个格式化程序来解析时间戳。自{unix epoch 以来,值DateTimeFormatter datetimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.S"); 似乎处于秒内,因此您可以使用ChronoField.INSTANT_SECONDS字段:

1520877600

然后你将上面的2个格式化程序加入到一个格式化程序中,使每个格式化程序都可选:

DateTimeFormatter timestampFormatter = new DateTimeFormatterBuilder()
    // parse timestamp value in seconds
    .appendValue(ChronoField.INSTANT_SECONDS)
    // create formatter
    .toFormatter();

另一个细节是DateTimeFormatter fmt = new DateTimeFormatterBuilder() // date/time .appendOptional(datetimeFormatter) // timestamp .appendOptional(timestampFormatter) // use JVM default timezone .toFormatter().withZone(ZoneId.systemDefault()); 方法,用于设置格式化程序使用的时区。这是因为unix时间戳表示自unix时期以来经过的时间计数,值1520877600可以表示不同的日期和时间,具体取决于您所在的时区。

我正在使用JVM默认时区(withZone),但您可以根据需要选择它。例如:如果我使用ZoneId.systemDefault(),时间戳将转换为纽约时区。使用不同的时区会影响年份和月份的值,特别是如果该值对应于该月的第一天或最后一天(如果我没有设置时区,则解析将因时间戳而失败,因为它需要一个时区将时间戳“翻译”为日期/时间。

无论如何,正如您想要的年份和月份值,最好的选择是直接解析为java.time.YearMonth,而{{3}}又可用于获取年份和月份的对应ZoneId.of("America/New_York")值:

int

答案 1 :(得分:1)

  val isoFormat = "(\\d{4})-(\\d{2})-(\\d{2}) (\\d{2})\\:(\\d{2})\\:(\\d{2})\\.(\\d+)".r 

  def getYear(timestamp: Any): Int = timestamp match {
      case isoFormat(year, month, day, hour, minute, second, millis) => year.toInt
      case l : Long => {
        val c = Calendar.getInstance()
        c.setTimeInMillis(l)
        c.get(Calendar.YEAR)
      }
      case _ => 2017
  }

  println(getYear("2018-03-31 14:12:00.231"))
  println(getYear(System.currentTimeMillis()))
  println(getYear("Foo"))

此示例使用scala的模式匹配语法。让我们从底部开始:

  • 如果给定的值既不是long的正确字符串,则返回2017默认值(可能希望使其可配置)
  • 如果值很长,请解析它 - 我在这种情况下使用Calendar来避免字符串转换,您可能想要添加时区
  • 如果代码是iso格式的字符串,请使用正则表达式提取我们想要的字段。这看起来像编译魔术,但只是使用scala的unapply方法进行模式匹配。您可以在此处找到正确的解释:REGULAR EXPRESSION PATTERNS。注意:为清晰起见,这可以写得更短,更详细。

我在上述方法中看到的主要好处是,使用其他日期格式扩展方法非常简单。

答案 2 :(得分:1)

此代码获取您的输入并获得年份。它使用SimpleDateFormat进行转换。

import java.text.SimpleDateFormat
import java.util.{Calendar, Date, GregorianCalendar}
import scala.util.{Failure, Success, Try}

def recognizeTimeStamp(timeStamp: String): Int = {

  val myCal = new GregorianCalendar();
  timeStamp match {
    case "unknown" => -1
    case x if x.replaceAll("\\d", "") == "" => {
      myCal.setTime(new Date(x.toLong))
      myCal.get(Calendar.YEAR)
    }

    case x =>
       val format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.S")
       Try(format.parse(x)) match {
            case Success(t) => {
                myCal.setTime(t)
                myCal.get(Calendar.YEAR)
            }
            case Failure(_) => -1
       }
   }
}

recognizeTimeStamp("2018-04-23 11:12:00.0")
recognizeTimeStamp("1334946600000")

来自我的Scala工作表的答案:

res0: Int = 2018
res1: Int = 2012

答案 3 :(得分:0)

我想出了评论中建议的解决方案。我创建了一个函数def isAllDigits(x: String) = x forall Character.isDigit并检查字符串是否都是数字。