【问题标题】:How to store time spent or total duration in Java?如何在 Java 中存储花费的时间或总持续时间?
【发布时间】:2017-12-24 20:09:13
【问题描述】:

我正在使用 Java 的 POI API 自动生成 Excel 报告。我将使用 POI 阅读、处理它们并创建新的 Excel 报告。

Excel 文件中的一列具有总花费时间,也就是说,它可以采用以下格式,46:23:12 - 读作46 hours, 23 minutes and 12 seconds

我了解如何读取日期和时间值,我通常将它们存储在 java.util.Date 中。这里的问题是这是一个持续时间,花费的时间可能超过 24 小时。哪种数据类型适合这个?以及如何使用 POI 阅读此内容?

【问题讨论】:

  • 你的 java 版本是多少?
  • 我可以根据需要使用任何一个。
  • 我不确定 POI 提供了哪些选项,但 Excel 将时间存储为一天的一小部分(即 0.5 表示下午 12:00)。因此,您可以尝试将该单元格读取为十进制数,然后将其转换为您需要的任何表示形式(例如 Duration)。

标签: java time apache-poi duration


【解决方案1】:

接受的答案是正确的,完全符合要求。这个答案提供了一些额外的细节以及从给定的46:23:12 字符串创建ISO-8601 standards 字符串的替代方法。

java.time.Duration 以 ISO-8601 标准为蓝本,并作为 JSR-310 implementation 的一部分与 Java-8 一起引入。 Java-9 引入了一些更方便的方法。

演示:

import java.time.Duration;

public class Main {
    public static void main(String[] args) {
        String iso8601DurationString = toIso8601DurationString("46:23:12");
        System.out.println(iso8601DurationString);

        Duration duration = Duration.parse(iso8601DurationString);
        // Default format
        System.out.println(duration);

        // Custom format
        // ####################################Java-8####################################
        String formattedDuration = String.format(
                "%02d Day %02d Hour %02d Minute %02d Second %d Millisecond %d Nanosecond", duration.toDays(),
                duration.toHours() % 24, duration.toMinutes() % 60, duration.toSeconds() % 60,
                duration.toMillis() % 1000, duration.toNanos() % 1000000000L);
        System.out.println(formattedDuration);
        // ##############################################################################

        // ####################################Java-9####################################
        formattedDuration = String.format("%02d Day %02d Hour %02d Minute %02d Second %d Millisecond %d Nanosecond",
                duration.toDaysPart(), duration.toHoursPart(), duration.toMinutesPart(), duration.toSecondsPart(),
                duration.toMillisPart(), duration.toNanosPart());
        System.out.println(formattedDuration);
        // ##############################################################################
    }

    static String toIso8601DurationString(String duration) {
        char[] symbols = "HMS".toCharArray();
        String[] durationParts = duration.split(":");
        StringBuilder sb = new StringBuilder("PT");
        for (int i = 0; i < durationParts.length; i++) {
            sb.append(durationParts[i]).append(symbols[i]);
        }
        return sb.toString();
    }
}

输出:

PT46H23M12S
PT46H23M12S
01 Day 22 Hour 23 Minute 12 Second 0 Millisecond 0 Nanosecond
01 Day 22 Hour 23 Minute 12 Second 0 Millisecond 0 Nanosecond

Trail: Date Time 了解现代日期时间 API。

【讨论】:

    【解决方案2】:

    Apache POI 支持的数据类型在here 中列出。

    我建议使用 0x15, "h:mm:ss"。

    您可以使用以下两个代码块进行读写。但读完后你应该手动解析字符串。

    将花费的总时间写入新文件:

    final HSSFWorkbook workbook = new HSSFWorkbook();
    final Sheet sheet = workbook.createSheet("SHEET ONE");
    
    final CellStyle style = workbook.createCellStyle();
    style.setDataFormat((short) 0x15);
    
    final Row completeRow = sheet.createRow(0);
    final Cell cell = completeRow.createCell(0);
    cell.setCellValue("46:23:12");
    cell.setCellStyle(style);
    
    FileOutputStream fileOutputStream = new FileOutputStream(new File("/tmp/one.xls"));
    workbook.write(fileOutputStream);
    fileOutputStream.close();
    

    从现有文件中读取总时间:

    FileInputStream fileInputStream = new FileInputStream("/tmp/one.xls");
    HSSFWorkbook workbook = new HSSFWorkbook(fileInputStream);
    HSSFSheet sheet = workbook.getSheet("SHEET ONE");
    
    for (Row row : sheet) {
        for (Cell cell : row) {
            final String stringCellValue = cell.getStringCellValue();
    
            System.out.println("stringCellValue = " + stringCellValue);
        }
    }
    
    fileInputStream.close();
    

    【讨论】:

      【解决方案3】:

      在 Java 8 中,时间量由 class java.time.Duration 表示。

      我不确定Apache POI是否有直接处理Duration的方法,所以我认为最好的方法是获取String的值, 然后解析此String 以获取值并将这些值添加到Duration

      String s = "46:23:12";
      String[] values = s.split(":");
      // get the hours, minutes and seconds value and add it to the duration
      Duration duration = Duration.ofHours(Integer.parseInt(values[0]));
      duration = duration.plusMinutes(Integer.parseInt(values[1]));
      duration = duration.plusSeconds(Integer.parseInt(values[2]));
      

      duration 对象将包含与输入等效的数量(在本例中:46 小时 23 分钟和 12 秒)。如果你调用duration.toString(),它会在ISO 8601 format中返回这个持续时间:

      PT46H23M12S


      当然,此代码假定输入 String 始终包含三个字段(小时、分钟和秒)。但是您可以在解析值之前检查values.length(并且仅当相应值不为零时才调用plus 方法)。


      如果您使用的是 Java ,则可以使用 ThreeTen Backport,它是 Java 8 新日期/时间类的一个很好的向后移植。对于Android,还有ThreeTenABP(更多关于如何使用它here)。

      唯一的区别是包名称(在 Java 8 中是 java.time,而在 ThreeTen Backport(或 Android 的 ThreeTenABP)中是 org.threeten.bp),但类和方法 名称 是相同的。

      【讨论】:

      【解决方案4】:

      Period 类可以在 Java 8 中使用。

      LocalDate startDate = LocalDate.of(year, month, day );
      LocalDate endDate = new LocalDate(year, month, day);
      
      Period diff = Period.between(startDate , endDate);
      

      当然,我想念这大约是几小时、几分钟和几秒钟。

      为此,有持续时间

      Duration timeDiff = Duration.ofMillis( startTime.getTime() , endTime.getTime() );
      

      【讨论】:

      • Duration 会更合适,因为Period 需要定义的开始和结束日期。
      • 啊,是的。对不起,OP。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-10-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多