在Java / Android中使用格里高利历时获取错误的时间戳值

时间:2016-07-12 18:06:07

标签: java android sqlite date datetime

我在Android中使用时间选择器和日期选择器对话框。为了保存日期和时间,我在Sqlite中使用 INTEGER 数据类型。所以我做了一些实用工具函数,将 DATE 从日期选择器对话框转换为 LONG(TIMESTAMP)格式,并将其转换回用户可读 DATE 。但不知何故,他们给了我错误的结果。

//Date Picker OnDateSetListener
 private DatePickerDialog.OnDateSetListener datePickerListener = new DatePickerDialog.OnDateSetListener(){

    @Override
    public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
        String dateText = getTimeString(year,monthOfYear,dayOfMonth);
        long date = Utility.getDateLong(year,monthOfYear,dayOfMonth);
        taskModel.setEndDate(date);
         endDateView.setText(dateText);
    }
};

 private String getTimeString(int year, int monthOfYear, int dayOfMonth){
    Log.i("set_date",monthOfYear+"");
    String yearText = String.valueOf(year);
    String monthText = String.valueOf(monthOfYear);
    String dayText = String.valueOf(dayOfMonth);
    return dayText+"/"+monthText+"/"+yearText;
}

//Utility Functions
//Getting long(TIMESTAMP) from DATE

public static long getDateLong(int year, int month, int day){
        Calendar calendar = new GregorianCalendar(year, month, day);
        Date date = calendar.getTime();
        long timeStamp = date.getTime();
        return timeStamp;
    }

//Converting TIMESTAMP to DATE
 public static String getDateFromLongValue(long d){
    Date date = new Date(d);
    //Calendar calendar = new GregorianCalendar();
    //calendar.setTimeInMillis(d);
    //return calendar.get(Calendar.DAY_OF_MONTH)+"/"+calendar.get(Calendar.MONTH)+"/"+calendar.get(Calendar.YEAR);

    DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy");
    String formattedDate = dateFormat.format(date);
    return formattedDate;
}

我输入的DATE错误的TIMESTAMP。例如,如果输入的日期是09-06-2016(" dd-MM-yyyy"),则转换后的长值为-876215232,当转换回日期时为22-12-1969。

此外,当我从选择器中选择DATE时,我错了一个月。即如果我选择第9个; 7月; 2016年, monthOfYear 属性我得到的是6而不是7。 有人可以指出错误。

2 个答案:

答案 0 :(得分:2)

确保您向GregorianCalendar构造函数传递的月份值是基于0的here

答案 1 :(得分:2)

TL;博士

LocalDate localDate = LocalDate.of( 2016 , 1 , 31 );  // 1 = January.
  • 使用java.time课程。 LocalDate按照您的预期计算数月:1-12。
  • YYYY-MM-DD文本而不是时间戳存储。

详细

Answer by MPelletier是正确的,您没有按照文档告诉您月份是从零开始计数(0-11)而不是从1开始(1-12)。疯狂的行为,是的。 许多的原因之一是避免使用与最早版本的Java捆绑在一起的这些设计糟糕的旧日期时间类。

java.time

相反,您应该使用Java 8及更高版本中内置的java.time框架。这些类取代了旧的麻烦的日期时间类,如java.util.Date& java.util.Calendar。见Oracle Tutorial。许多java.time功能都被反向移植到Java 6& ThreeTen-Backport中的7,并在ThreeTenABP中进一步适应Android。

LocalDate

对于没有时间且没有时区的仅限日期的值,请使用LocalDate类。月份数字是理智的,1-12。

LocalDate localDate = LocalDate.of( 2016 , 1 , 31 );

或者使用方便的Month枚举。

LocalDate localDate = LocalDate.of( 2016 , Month.JANUARY , 31 );

日期部分

您可以查询每个部分,年,月和日期。

int year = localDate.getYear();
int month = localDate.getMonthValue();
int dayOfMonth = localDate.getDayOfMonth();

时区

捕获当前日期时,请务必指定时区。对于任何特定时刻,日期在全球范围内因地区而异。

ZoneId zoneId = ZoneId.of( "America/Montreal" );
LocalDate today = LocalDate.now( zoneID );

ISO 8601

使用count-of-milliseconds-from - epoch对于仅限日期的值没有意义。鉴于SQLite有no true data types,并且没有任何东西可以支持SQL标准DATE列,我建议存储一个表示日期值的String。具体而言,以ISO 8601标准定义的格式创建String。在解析和生成字符串时,java.time类在默认情况下使用此标准的格式。 YYYY-MM-DD的标准格式恰好按时间顺序按字母顺序排序。

String string = localDate.toString(); // 2016-01-31
LocalDate localDate = LocalDate.parse( string );

如果使用符合JDBC 4.2的驱动程序,您可以通过LocalDate通过getObject / setObject传递PreparedStatement

摘要

所以LocalDate与旧类相比是:

  • 更合乎逻辑(理智的月份计数1-12)
  • 更容易使用字符串(直接解析/生成标准格式)
  • 真正代表仅限日期的值