Java:将字符串转换为时间戳

97

我在尝试将 String 转换为 TimeStamp 时遇到了问题。我有一个数组,其日期格式为 yyyy-MM-dd,我想将其更改为 yyyy-MM-dd HH:mm:ss.SSS 格式。所以,我使用了以下代码:

final String OLD_FORMAT = "yyyy-MM-dd";
final String NEW_FORMAT = "yyyy-MM-dd HH:mm:ss.SSS";
String oldDateString = createdArray[k];
String newDateString;
                
final DateFormat formatter = new SimpleDateFormat(OLD_FORMAT);
final Date d = formatter.parse(oldDateString);
((SimpleDateFormat) formatter).applyPattern(NEW_FORMAT);
newDateString = formatter.format(d);
System.out.println(newDateString);
                
final Timestamp ts = Timestamp.valueOf(newDateString);
System.out.println(ts);

然后我得到了以下结果。

2009年10月20日00:00:00.000

2009年10月20日00:00:00.0

但是当我尝试简单地执行

final String text = "2011-10-02 18:48:05.123";
ts = Timestamp.valueOf(text);
System.out.println(ts);

我得到了正确的结果:

2011年10月02日18:48:05.123

你知道我可能做错了什么吗?

谢谢帮助。


只需使用两个(Simple)DateFormat实例,无需调整“applyPattern()”。 - Gyro Gearless
@GyroGearless 我不确定你的意思是什么?怎么可能不应用模式? - Dimitra Micha
@Piro 错误在于我有2009-10-20 00:00:00.0而不是2009-10-20 00:00:00.000。 - Dimitra Micha
为什么需要三个位置/零? 时间戳使用它自己的格式,该格式是正确的,不能更改。如果您需要打印格式化的时间戳,请将其从时间戳转换回日期并进行格式化。当前的答案似乎完全忽略了您的需求,因为您的问题不明显。 - Piro
@Piro 因为当我尝试在 MSSQL 中使用 .statement.setTimestamp(19,timestamp); 时,它会出现以下错误:"在将 nvarchar 数据类型转换为 datetime 数据类型时,值超出范围。" - Dimitra Micha
显示剩余3条评论
11个回答

137

按照以下步骤进行操作以获得正确的结果:

try {
    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss.SSS");
    Date parsedDate = dateFormat.parse(yourString);
    Timestamp timestamp = new java.sql.Timestamp(parsedDate.getTime());
} catch(Exception e) { //this generic but you can control another types of exception
    // look the origin of excption 
}
请注意,.parse(String) 方法可能会抛出 ParseException 异常。

我尝试了您建议的方法,但它抛出了一个异常。我能修复它吗? - Dimitra Micha
4
这种日期格式很危险:hh 会按照"上午/下午(1-12小时制)"来解释小时。你应该使用 HH 来获取"一天中的小时(0-23小时制)",就像问题中一样。 - Scolytus

27
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Util {
  public static Timestamp convertStringToTimestamp(String strDate) {
    try {
      DateFormat formatter = new SimpleDateFormat("dd/MM/yyyy");
       // you can change format of date
      Date date = formatter.parse(strDate);
      Timestamp timeStampDate = new Timestamp(date.getTime());

      return timeStampDate;
    } catch (ParseException e) {
      System.out.println("Exception :" + e);
      return null;
    }
  }
}

3
我更喜欢这个答案,因为它展示了代码中所使用的类。我一直遇到错误是因为我导入了 java.sql.Date 而不是 java.util.Date - tartaruga_casco_mole

19

我愿意提供现代的答案。在2013年提出这个问题时,使用Timestamp类是正确的,例如将日期时间存储到数据库中。但是现在这个类已经过时了。现代Java日期和时间API于2014年春季随Java 8一起推出,已经有三年半的历史了。我建议你使用它。

根据你的情况和需求,有两个自然的替代品可以取代Timestamp:

  • Instant是时间轴上的一个点。对于大多数目的,我认为这是最安全的选择。一个Instant与时区无关,并且通常可以在客户端设备和数据库服务器使用不同的时区的情况下正常工作。
  • LocalDateTime是没有时区的日期和时间,例如2011-10-02 18:48:05.123(引用该问题)。

现代的JDBC驱动程序(JDBC 4.2或更高版本)和其他用于数据库访问的现代工具都可以将InstantLocalDateTime存储到数据类型为timestamp的数据库列中。本答案中使用的这两个类和其他日期时间类属于称为java.time或JSR-310的现代API。

最简单的方法是将你的字符串转换为LocalDateTime,因此让我们先来处理它:

    DateTimeFormatter formatter
            = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.SSS");
    String text = "2011-10-02 18:48:05.123";
    LocalDateTime dateTime = LocalDateTime.parse(text, formatter);
    System.out.println(dateTime);

这会打印

2011-10-02T18:48:05.123

如果您的字符串是以yyyy-MM-dd格式表示的,那么请改为:

    String text = "2009-10-20";
    LocalDateTime dateTime = LocalDate.parse(text).atStartOfDay();
    System.out.println(dateTime);

这会打印出来

2009-10-20T00:00

或者更好的方式是,使用LocalDate.parse()函数的输出,并将其存储到数据类型为date的数据库列中。

在两种情况下,从LocalDateTime转换为Instant的步骤如下:

    Instant ts = dateTime.atZone(ZoneId.systemDefault()).toInstant();
    System.out.println(ts);

我已经指定了一个转换,使用JVM的默认时区,因为这是过时类所使用的。然而,这种方式很容易出问题,因为时区设置可能会被程序中其他部分或者运行在同一JVM中的其他程序更改。如果可以的话,最好指定以地区/城市格式的时区,例如:

    Instant ts = dateTime.atZone(ZoneId.of("Europe/Athens")).toInstant();

所给出的答案是基于提问者的问题而给出的,而不是对错。 - Ojonugwa Jude Ochalifu
3
你是完全正确的,@OjonugwaJudeOchalifu。由于这个问题和答案都会保存下来供后人查看,问题在于我们应该让2013年的回答独立存在,还是应该补充一份回答以展示未来的最佳解决方案。 - Ole V.V.

11

将字符串转换为java.sql.Timestamp的简单方法:

Timestamp t = new Timestamp(DateUtil.provideDateFormat().parse("2019-01-14T12:00:00.000Z").getTime());

DateUtil.java:

import java.text.SimpleDateFormat;
import java.util.TimeZone;

public interface DateUtil {

  String ISO_DATE_FORMAT_ZERO_OFFSET = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
  String UTC_TIMEZONE_NAME = "UTC";

  static SimpleDateFormat provideDateFormat() {
    SimpleDateFormat simpleDateFormat = new SimpleDateFormat(ISO_DATE_FORMAT_ZERO_OFFSET);
    simpleDateFormat.setTimeZone(TimeZone.getTimeZone(UTC_TIMEZONE_NAME));
    return simpleDateFormat;
  }
}

1
这是一个很棒的解决方案。 - vinicius gati
@ChristophRaab 我相信你应该把类/接口添加到你的解决方案中。 - Darren S

4

为了完整起见,这里提供一个使用lambda表达式和方法引用的解决方案:

ISO格式?

描述: 以下方法

  • 将按照模式yyyy-MM-ddString转换为Timestamp,如果输入有效,则返回一个时间戳。
  • 如果给定null值,则返回null
  • 如果给定无效输入,则抛出DateTimeParseException异常

代码

static Timestamp convertStringToTimestamp(String strDate) {
    return Optional.ofNullable(strDate) // wrap the String into an Optional
                   .map(str -> LocalDate.parse(str).atStartOfDay()) // convert into a LocalDate and fix the hour:minute:sec to 00:00:00
                   .map(Timestamp::valueOf) // convert to Timestamp
                   .orElse(null); // if no value is present, return null
}


验证: 这种方法可以使用以下单元测试进行测试: (使用Junit5Hamcrest

@Test
void convertStringToTimestamp_shouldReturnTimestamp_whenValidInput() {
    // given
    String strDate = "2020-01-30";

    // when
    final Timestamp result = convertStringToTimestamp(strDate);

    // then
    final LocalDateTime dateTime = LocalDateTime.ofInstant(result.toInstant(), ZoneId.systemDefault());
    assertThat(dateTime.getYear(), is(2020));
    assertThat(dateTime.getMonthValue(), is(1));
    assertThat(dateTime.getDayOfMonth(), is(30));
}

@Test
void convertStringToTimestamp_shouldReturnTimestamp_whenInvalidInput() {
    // given
    String strDate = "7770-91-30";

    // when, then
    assertThrows(DateTimeParseException.class, () -> convertStringToTimestamp(strDate));
}

@Test
void convertStringToTimestamp_shouldReturnTimestamp_whenNullInput() {
    // when
    final Timestamp result = convertStringToTimestamp(null);

    // then
    assertThat(result, is(nullValue()));
}


另一种格式?

通常,需要解析的字符串会以另一种格式出现。一种处理方式是使用格式化程序将其转换为另一种格式。以下是一个示例:

输入:20200130 11:30

模式:yyyyMMdd HH:mm

输出:此输入的时间戳

代码

static Timestamp convertStringToTimestamp(String strDate) {
    final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd HH:mm");
    return Optional.ofNullable(strDate) //
                   .map(str -> LocalDateTime.parse(str, formatter))
                   .map(Timestamp::valueOf) //
                   .orElse(null);
}

测试:

@Test
void convertStringToTimestamp_shouldReturnTimestamp_whenValidInput() {
    // given
    String strDate = "20200130 11:30";

    // when
    final Timestamp result = convertStringToTimestamp(strDate);

    // then
    final LocalDateTime dateTime = LocalDateTime.ofInstant(result.toInstant(), ZoneId.systemDefault());
    assertThat(dateTime.getYear(), is(2020));
    assertThat(dateTime.getMonthValue(), is(1));
    assertThat(dateTime.getDayOfMonth(), is(30));
    assertThat(dateTime.getHour(), is(11));
    assertThat(dateTime.getMinute(), is(30));
}

3
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");

Date date = formatter.parse(dateString);

Timestamp timestamp = new Timestamp(date.getTime());

System.out.println(timestamp);

当您格式化字符串日期时,可能需要捕获解析异常。 - eyoeldefare

2
DateFormat formatter;
formatter = new SimpleDateFormat("dd/MM/yyyy");
Date date = (Date) formatter.parse(str_date);
java.sql.Timestamp timeStampDate = new Timestamp(date.getTime());

2
这是我所做的:
Timestamp timestamp = Timestamp.valueOf(stringValue);

其中stringValue可以是任何日期/时间格式。


不,Timestamp.valueOf() 不接受任何日期和时间格式。例如问题中的 旧格式 yyyy-MM-dd。而且我仍然相信不应再使用 Timestamp 类了。它的设计很差,是对已经设计不良的 Date 类的一个真正的 hack。曾经用于在 SQL 数据库之间传输值,但今天建议使用OffsetDateTimeLocalDateTimeInstant 代替。 - Ole V.V.

0
首先,将您的日期字符串转换为date,然后使用以下一组代码将其转换为timestamp
final Date date = new Date();
final Timestamp timestamp = new Timestamp(date.getTime()); // Instead of date, put your converted date
final Timestamp myTimeStamp = timestamp;

2
我不确定如何放置我的转换日期。我想我的问题始于 ((SimpleDateFormat) formatter).applyPattern(NEW_FORMAT); ? 当我使用我的日期,Date d,它仍然产生错误的结果:2009-10-20 00:00:00.0 - Dimitra Micha

0

你能试一下吗...

String dob="your date String";
String dobis=null;
final DateFormat df = new SimpleDateFormat("yyyy-MMM-dd");
final Calendar c = Calendar.getInstance();
try {
    if(dob!=null && !dob.isEmpty() && dob != "")
    {
    c.setTime(df.parse(dob));
    int month=c.get(Calendar.MONTH);
    month=month+1;
    dobis=c.get(Calendar.YEAR)+"-"+month+"-"+c.get(Calendar.DAY_OF_MONTH);
    }

}

8
dob != ""是多余的和错误的 - 永远不要使用==!=来比较字符串。而且你不应该以那种方式格式化日期,这就是(简单)日期格式化程序的作用。 - Gyro Gearless

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接