当前位置: 首页 > 知识库问答 >
问题:

如何在使用Java8日期时间API时将AM/PM符号更改为我自己的字母表

澹台成龙
2023-03-14

我们有一个应用程序,可以接受客户提供的日期时间格式。

我们最近开始迁移到Java8新的日期时间API,因为它们是线程安全的。在准备格式化程序之前,请看下面的代码,我们将A和P设置为AM

String[] AMPM = new String[2];
AMPM[0] = "A";
AMPM[1] = "P";
DateFormatSymbols dfs = new DateFormatSymbols(locale);
dfs.setAmPmStrings(AMPM);
sdf = new SimpleDateFormat(format, dfs);  

但有了新的Java8日期时间API,我看不到如何定义它。但在谷歌搜索了几次之后,我发现我们必须使用DateTimeFormatterBuilder,但这只有在我自己构建模式时才有用;这里我们从客户那里收到了完整的日期时间模式

关于如何使用Java8做到这一点的任何提示。

共有1个答案

冉伯寅
2023-03-14

您可以使用DateTimeFormatterBuilder。appendText()方法,该方法获取带有自定义值的映射。

根据javadoc,字段AMPM_OF_DAY可以有值0表示AM1表示PM,因此您只需创建一个包含这些值的map并将其传递给格式化程序:

import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;
import java.time.LocalTime;

// create map with custom values (0=AM, 1=PM, mapping to values "A" and "P")
Map<Long, String> map = new HashMap<>();
map.put(0L, "A"); // AM mapped to "A"
map.put(1L, "P"); // PM mapped to "P"

DateTimeFormatter formatter = new DateTimeFormatterBuilder()
    // hour/minute/second (change to whatever pattern you need)
    .appendPattern("hh:mm:ss ")
    // use the mapped values
    .appendText(ChronoField.AMPM_OF_DAY, map)
    // create formatter
    .toFormatter();

// testing
System.out.println(formatter.format(LocalTime.of(10, 30, 45))); // 10:30:45 A
System.out.println(formatter.format(LocalTime.of(22, 30, 45))); // 10:30:45 P

输出将是:

10:30:45 A
10:30:45 P

它还可以解析字符串

System.out.println(LocalTime.parse("10:20:30 A", formatter)); // 10:20:30
System.out.println(LocalTime.parse("10:20:30 P", formatter)); // 22:20:30

输出将是:

10:20:30
22:20:30

如果不控制模式,可以查找字母a(对应于AM/PM字段的模式),并用自定义版本替换它。

一种替代方法是拆分格式String,使用a作为分隔符,这样就不会丢失模式的其余部分:

// format with day/month/year hour:minute:second am/pm timezone
String format = "dd/MM/yyyy hh:mm:ss a z";

// split the format ("a" is the AM/PM field)
String[] formats = format.split("a");

DateTimeFormatterBuilder builder = new DateTimeFormatterBuilder()
    // first part of the pattern (everything before "a")
    .appendPattern(formats[0])
    // use the AM/PM mapped values
    .appendText(ChronoField.AMPM_OF_DAY, map);

// if there's something after the "a", add it
if (formats.length > 1) {
    builder.appendPattern(formats[1]);
}

// create formatter
DateTimeFormatter formatter = builder.toFormatter();

//test
ZonedDateTime z = ZonedDateTime.of(2017, 5, 1, 10, 20, 30, 0, ZoneId.of("America/Sao_Paulo"));
// AM replaced by "A"
System.out.println(formatter.format(z)); // 01/05/2017 10:20:30 A BRT

如果a在开头或结尾,或者即使没有a(在这种情况下,我在结尾添加,如果不存在,我不确定是否必须添加),该算法也可以工作。

// "a" in the end
String format = "hh:mm:ss a";
DateTimeFormatter formatter = // use same code above
System.out.println(formatter.format(LocalTime.of(15, 30))); // 03:30:00 P

// "a" in the beginning
String format = "a hh:mm:ss";
DateTimeFormatter formatter = // use same code above
System.out.println(formatter.format(LocalTime.of(15, 30))); // P 03:30:00

// no "a" (field is added in the end)
String format = "HH:mm:ss";
DateTimeFormatter formatter = // use same code above
System.out.println(formatter.format(LocalTime.of(15, 30))); // 03:30:00P

你可以做一些改进,比如如果格式不包含a,那么就不要添加它(或者在它前面添加空格),或者任何你想要的东西。

PS:此代码不处理文字('中的文本),如"dd/MM/yyyy'at'hh: mm: ss a"("at"是文字,不应删除/替换)。

我不是正则表达式专家(所以我不能100%确定它是否适用于所有情况),但你可以做这样的事情:

String[] formats = format.split("(?<!\'[^\']{0,20})a|a(?![^\']{0,20}\')");

此正则表达式将忽略引用文本中的a。我必须使用{0,20}量词,因为lookahead和lookbehinds(?模式)不接受*,所以如果在“a”之前或之后引用的文本最多有20个字符(只需将此值更改为您认为最适合您的用例的值),这将起作用。

一些测试:

String format = "\'Time: at\' hh:mm:ss a";
DateTimeFormatter formatter = // use same code above, but with the modified regex split
System.out.println(formatter.format(LocalTime.of(15, 30))); // Time: at 03:30:00 P

String format = "dd/MM/yyyy \'at\' hh:mm:ss a z";
DateTimeFormatter formatter = // use same code above, but with the modified regex split
ZonedDateTime z = ZonedDateTime.of(2017, 5, 1, 10, 20, 30, 0, ZoneId.of("America/Sao_Paulo"));
System.out.println(formatter.format(z)); // 01/05/2017 at 10:20:30 A BRT
 类似资料:
  • 我得到一个变量字符串,如下所示: 上午8点45分 如果是下午,则希望将其转换为24小时制。这样我就可以放下am/pm,用它来做别的事情。 我可以像这样轻松地放弃am/pm: 当然,如果我这样做,我不知道字符串是am还是pm,所以我不知道在字符串上加上12小时,使它成为24小时。 有人知道我该如何解决这个问题吗?我绝对无法更改我得到的变量输入,它将始终是小时(在 12 小时内)、分钟和 am 或 p

  • 问题内容: string : 2014-04-25 17:03:13 使用SimpleDateFormat足以格式化吗?否则我将转向任何新的API? 我的预期结果是(印度区域): 问题答案: 记住对象没有固有的格式,您需要两个对象来产生想要的结果-一个要解析,另一个要格式化: 输出: 请注意,在格式中使用带引号的序列(例如),它被视为格式模式中的文字。

  • 使用SimpleDateFormat就足以格式化?否则我会转移到任何新的API? 我的预期结果是(印度区):

  • 我想在SQL Oracle中将日期的格式更改为HH:MI:SS PM/AM格式。 我想在这样的情况下使用它: case when to\u char(a.dtime,'HH:MI:SS') 但是SQL不想显示所有to\u char时间 并且它不适用于to\u date。有什么建议吗?提前非常感谢。

  • 问题内容: 您如何以12小时格式(AM / PM)显示JavaScript日期时间对象? 问题答案:

  • 我在这里有我的日期来自我的API,我试图在其中解析到。我使用intl包尝试了以下方法,但我遇到了错误 未处理的异常:格式异常:尝试从 2020/07/07 09:47:54 在位置 20 读取 有人知道这里出了什么问题吗?