寻求支持类JIRA时间格式的时间解析库:可转Millis并做timestamp运算
嘿,针对你要解析2y 1M 3w 4d 12h 20m 10s这种时间跨度字符串、转成毫秒后和时间戳做加减的需求,我给你几个实际项目里用过的靠谱方案,分语言给你说:
Java 8+ 原生方案(无需第三方库)
如果你用的是Java 8及以上版本,完全可以用自带的日期API搞定,只需要写个简单的正则解析逻辑就行。需要注意的是,年、月这类单位的时长不固定(比如2月有28/29天,闰年366天),必须基于给定的时间戳来计算才准确:
import java.time.*; import java.util.regex.Matcher; import java.util.regex.Pattern; public class TimeSpanParser { // 匹配你的时间格式的正则 private static final Pattern TIME_SPAN_PATTERN = Pattern.compile( "(?:(\\d+)y\\s?)?" + "(?:(\\d+)M\\s?)?" + "(?:(\\d+)w\\s?)?" + "(?:(\\d+)d\\s?)?" + "(?:(\\d+)h\\s?)?" + "(?:(\\d+)m\\s?)?" + "(?:(\\d+)s\\s?)?" ); // 解析时间跨度并和时间戳做加法,减法的话把plus改成minus就行 public static long calculateNewTimestamp(String timeSpan, long originalTimestamp) { Matcher matcher = TIME_SPAN_PATTERN.matcher(timeSpan.trim()); if (!matcher.matches()) { throw new IllegalArgumentException("格式不对哦,得是类似2y 1M 3w这种格式"); } // 把时间戳转成LocalDateTime,方便做时间加减 LocalDateTime baseTime = Instant.ofEpochMilli(originalTimestamp) .atZone(ZoneId.systemDefault()) .toLocalDateTime(); // 逐个解析单位并做加减 if (matcher.group(1) != null) baseTime = baseTime.plusYears(Long.parseLong(matcher.group(1))); if (matcher.group(2) != null) baseTime = baseTime.plusMonths(Long.parseLong(matcher.group(2))); if (matcher.group(3) != null) baseTime = baseTime.plusWeeks(Long.parseLong(matcher.group(3))); if (matcher.group(4) != null) baseTime = baseTime.plusDays(Long.parseLong(matcher.group(4))); if (matcher.group(5) != null) baseTime = baseTime.plusHours(Long.parseLong(matcher.group(5))); if (matcher.group(6) != null) baseTime = baseTime.plusMinutes(Long.parseLong(matcher.group(6))); if (matcher.group(7) != null) baseTime = baseTime.plusSeconds(Long.parseLong(matcher.group(7))); // 转回到毫秒时间戳 return baseTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(); } // 示例用法 public static void main(String[] args) { String timeSpan = "2y 1M 3w 4d 12h 20m 10s"; long now = System.currentTimeMillis(); long newTime = calculateNewTimestamp(timeSpan, now); System.out.println("原始时间戳:" + now); System.out.println("加完跨度后的时间戳:" + newTime); } }
Java 7及以下:用Joda-Time库
如果还在维护Java 7的老项目,Joda-Time绝对是首选,它的时间处理API比原生的好用太多,而且能直接解析你这种格式:
import org.joda.time.*; import org.joda.time.format.PeriodFormatter; import org.joda.time.format.PeriodFormatterBuilder; public class JodaTimeParser { private static final PeriodFormatter FORMATTER = new PeriodFormatterBuilder() .appendYears().appendSuffix("y ") .appendMonths().appendSuffix("M ") .appendWeeks().appendSuffix("w ") .appendDays().appendSuffix("d ") .appendHours().appendSuffix("h ") .appendMinutes().appendSuffix("m ") .appendSeconds().appendSuffix("s") .toFormatter(); public static long calculateNewTimestamp(String timeSpan, long originalTimestamp) { Period period = FORMATTER.parsePeriod(timeSpan.trim()); DateTime baseTime = new DateTime(originalTimestamp); // 减法的话用minus(period) return baseTime.plus(period).getMillis(); } public static void main(String[] args) { String timeSpan = "2y 1M 3w 4d 12h 20m 10s"; long now = System.currentTimeMillis(); System.out.println("新时间戳:" + calculateNewTimestamp(timeSpan, now)); } }
Python 方案(原生库搞定)
Python的话,标准库datetime加正则就能解决,唯一需要注意的是timedelta不支持年、月,得手动处理:
import re from datetime import datetime, timedelta def calculate_new_timestamp(time_span, original_timestamp): pattern = re.compile( r'(?:(\d+)y\s?)?' r'(?:(\d+)M\s?)?' r'(?:(\d+)w\s?)?' r'(?:(\d+)d\s?)?' r'(?:(\d+)h\s?)?' r'(?:(\d+)m\s?)?' r'(?:(\d+)s\s?)?' ) match = pattern.fullmatch(time_span.strip()) if not match: raise ValueError("格式不对,请输入类似2y 1M 3w的字符串") # 把毫秒时间戳转成datetime(Python的timestamp是秒级,所以除以1000) base_dt = datetime.fromtimestamp(original_timestamp / 1000) # 处理年和月 years = int(match.group(1)) if match.group(1) else 0 months = int(match.group(2)) if match.group(2) else 0 if years or months: new_year = base_dt.year + years new_month = base_dt.month + months # 处理月份溢出(比如12月加1月变成次年1月) new_year += (new_month - 1) // 12 new_month = (new_month - 1) % 12 + 1 # 处理日期超出当月天数的情况(比如3月31日加1月变成4月30日) try: base_dt = base_dt.replace(year=new_year, month=new_month) except ValueError: base_dt = base_dt.replace(year=new_year, month=new_month, day=1) + timedelta(days=32) base_dt = base_dt.replace(day=1) - timedelta(days=1) # 处理周、天、时、分、秒 delta = timedelta( weeks=int(match.group(3)) if match.group(3) else 0, days=int(match.group(4)) if match.group(4) else 0, hours=int(match.group(5)) if match.group(5) else 0, minutes=int(match.group(6)) if match.group(6) else 0, seconds=int(match.group(7)) if match.group(7) else 0 ) new_dt = base_dt + delta # 减法的话改成base_dt - delta # 转回毫秒时间戳 return int(new_dt.timestamp() * 1000) # 示例用法 if __name__ == "__main__": time_span = "2y 1M 3w 4d 12h 20m 10s" now = 1690000000000 # 示例毫秒时间戳 print("新时间戳:", calculate_new_timestamp(time_span, now))
几个关键提醒
- 年、月不能直接转固定毫秒:因为它们的时长不是固定值,必须基于具体的时间戳计算才准确。
- 格式兼容:如果你的输入可能没有空格(比如
2y1M3w),把正则里的\s?改成\s*或者直接去掉就行。 - 减法运算:只需要把代码里的加法操作改成减法(比如Java的
plus改成minus,Python的+改成-)。
内容的提问来源于stack exchange,提问作者mongolol
相关产品推荐
相关产品推荐

