Commit 45cda665 authored by ma yanling's avatar ma yanling
Browse files

project commit

parent ad2fb30a
Pipeline #2354 failed with stages
in 0 seconds
package cn.hutool.core.convert.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.AbstractConverter;
import cn.hutool.core.convert.ConvertException;
import cn.hutool.core.convert.ConverterRegistry;
import cn.hutool.core.lang.Pair;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.TypeUtil;
import java.lang.reflect.Type;
import java.util.Map;
public class PairConverter extends AbstractConverter<Pair<?, ?>> {
/** Pair类型 */
private final Type pairType;
/** 键类型 */
private final Type keyType;
/** 值类型 */
private final Type valueType;
/**
* 构造,Pair的key和value泛型类型自动获取
*
* @param pairType Map类型
*/
public PairConverter(Type pairType) {
this(pairType, null, null);
}
/**
* 构造
*
* @param pairType Pair类型
* @param keyType 键类型
* @param valueType 值类型
*/
public PairConverter(Type pairType, Type keyType, Type valueType) {
this.pairType = pairType;
this.keyType = keyType;
this.valueType = valueType;
}
@SuppressWarnings("rawtypes")
@Override
protected Pair<?, ?> convertInternal(Object value) {
Map map = null;
if (value instanceof Map.Entry) {
final Map.Entry entry = (Map.Entry) value;
map = MapUtil.of(entry.getKey(), entry.getValue());
}else if (value instanceof Map) {
map = (Map) value;
} else if (value instanceof CharSequence) {
final CharSequence str = (CharSequence) value;
map = strToMap(str);
} else if (BeanUtil.isReadableBean(value.getClass())) {
map = BeanUtil.beanToMap(value);
}
if (null != map) {
return mapToPair(pairType, keyType, valueType, map);
}
throw new ConvertException("Unsupported to map from [{}] of type: {}", value, value.getClass().getName());
}
/**
* 字符串转单个键值对的Map,支持分隔符{@code :}、{@code =}、{@code ,}
*
* @param str 字符串
* @return map or null
*/
private static Map<CharSequence, CharSequence> strToMap(final CharSequence str) {
// key:value key=value key,value
final int index = StrUtil.indexOf(str, '=', 0, str.length());
if (index > -1) {
return MapUtil.of(str.subSequence(0, index + 1), str.subSequence(index, str.length()));
}
return null;
}
/**
* Map转Entry
*
* @param targetType 目标的Map类型
* @param keyType 键类型
* @param valueType 值类型
* @param map 被转换的map
* @return Entry
*/
@SuppressWarnings("rawtypes")
private static Pair<?, ?> mapToPair(final Type targetType, final Type keyType, final Type valueType, final Map map) {
Object key = null;
Object value = null;
if (1 == map.size()) {
final Map.Entry entry = (Map.Entry) map.entrySet().iterator().next();
key = entry.getKey();
value = entry.getValue();
} else if (2 == map.size()) {
key = map.get("key");
value = map.get("value");
}
final ConverterRegistry convert = ConverterRegistry.getInstance();
return (Pair<?, ?>) ReflectUtil.newInstance(TypeUtil.getClass(targetType),
TypeUtil.isUnknown(keyType) ? key : convert.convert(keyType, key),
TypeUtil.isUnknown(valueType) ? value : convert.convert(valueType, value)
);
}
}
package cn.hutool.core.convert.impl;
import java.io.File;
import java.net.URI;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;
import cn.hutool.core.convert.AbstractConverter;
/**
* 字符串转换器
* @author Looly
*
*/
public class PathConverter extends AbstractConverter<Path>{
private static final long serialVersionUID = 1L;
@Override
protected Path convertInternal(Object value) {
try {
if(value instanceof URI){
return Paths.get((URI)value);
}
if(value instanceof URL){
return Paths.get(((URL)value).toURI());
}
if(value instanceof File){
return ((File)value).toPath();
}
return Paths.get(convertToStr(value));
} catch (Exception e) {
// Ignore Exception
}
return null;
}
}
package cn.hutool.core.convert.impl;
import cn.hutool.core.convert.AbstractConverter;
import java.time.Period;
import java.time.temporal.TemporalAmount;
/**
*
* {@link Period}对象转换器
*
* @author Looly
* @since 5.0.0
*/
public class PeriodConverter extends AbstractConverter<Period> {
private static final long serialVersionUID = 1L;
@Override
protected Period convertInternal(Object value) {
if(value instanceof TemporalAmount){
return Period.from((TemporalAmount) value);
}else if(value instanceof Integer){
return Period.ofDays((Integer) value);
} else {
return Period.parse(convertToStr(value));
}
}
}
package cn.hutool.core.convert.impl;
import cn.hutool.core.convert.AbstractConverter;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.convert.ConvertException;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import java.util.function.Function;
/**
* 原始类型转换器<br>
* 支持类型为:<br>
* <ul>
* <li>{@code byte}</li>
* <li>{@code short}</li>
* <li>{@code int}</li>
* <li>{@code long}</li>
* <li>{@code float}</li>
* <li>{@code double}</li>
* <li>{@code char}</li>
* <li>{@code boolean}</li>
* </ul>
*
* @author Looly
*/
public class PrimitiveConverter extends AbstractConverter<Object> {
private static final long serialVersionUID = 1L;
private final Class<?> targetType;
/**
* 构造<br>
*
* @param clazz 需要转换的原始
* @throws IllegalArgumentException 传入的转换类型非原始类型时抛出
*/
public PrimitiveConverter(Class<?> clazz) {
if (null == clazz) {
throw new NullPointerException("PrimitiveConverter not allow null target type!");
} else if (false == clazz.isPrimitive()) {
throw new IllegalArgumentException("[" + clazz + "] is not a primitive class!");
}
this.targetType = clazz;
}
@Override
protected Object convertInternal(Object value) {
return PrimitiveConverter.convert(value, this.targetType, this::convertToStr);
}
@Override
protected String convertToStr(Object value) {
return StrUtil.trim(super.convertToStr(value));
}
@Override
@SuppressWarnings("unchecked")
public Class<Object> getTargetType() {
return (Class<Object>) this.targetType;
}
/**
* 将指定值转换为原始类型的值
* @param value 值
* @param primitiveClass 原始类型
* @param toStringFunc 当无法直接转换时,转为字符串后再转换的函数
* @return 转换结果
* @since 5.5.0
*/
protected static Object convert(Object value, Class<?> primitiveClass, Function<Object, String> toStringFunc) {
if (byte.class == primitiveClass) {
return ObjectUtil.defaultIfNull(NumberConverter.convert(value, Byte.class, toStringFunc), 0);
} else if (short.class == primitiveClass) {
return ObjectUtil.defaultIfNull(NumberConverter.convert(value, Short.class, toStringFunc), 0);
} else if (int.class == primitiveClass) {
return ObjectUtil.defaultIfNull(NumberConverter.convert(value, Integer.class, toStringFunc), 0);
} else if (long.class == primitiveClass) {
return ObjectUtil.defaultIfNull(NumberConverter.convert(value, Long.class, toStringFunc), 0);
} else if (float.class == primitiveClass) {
return ObjectUtil.defaultIfNull(NumberConverter.convert(value, Float.class, toStringFunc), 0);
} else if (double.class == primitiveClass) {
return ObjectUtil.defaultIfNull(NumberConverter.convert(value, Double.class, toStringFunc), 0);
} else if (char.class == primitiveClass) {
return Convert.convert(Character.class, value);
} else if (boolean.class == primitiveClass) {
return Convert.convert(Boolean.class, value);
}
throw new ConvertException("Unsupported target type: {}", primitiveClass);
}
}
package cn.hutool.core.convert.impl;
import cn.hutool.core.convert.AbstractConverter;
import cn.hutool.core.convert.ConverterRegistry;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.TypeUtil;
import java.lang.ref.Reference;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.lang.reflect.Type;
/**
* {@link Reference}转换器
*
* @author Looly
* @since 3.0.8
*/
@SuppressWarnings("rawtypes")
public class ReferenceConverter extends AbstractConverter<Reference> {
private static final long serialVersionUID = 1L;
private final Class<? extends Reference> targetType;
/**
* 构造
* @param targetType {@link Reference}实现类型
*/
public ReferenceConverter(Class<? extends Reference> targetType) {
this.targetType = targetType;
}
@SuppressWarnings("unchecked")
@Override
protected Reference<?> convertInternal(Object value) {
//尝试将值转换为Reference泛型的类型
Object targetValue = null;
final Type paramType = TypeUtil.getTypeArgument(targetType);
if(false == TypeUtil.isUnknown(paramType)){
targetValue = ConverterRegistry.getInstance().convert(paramType, value);
}
if(null == targetValue){
targetValue = value;
}
if(this.targetType == WeakReference.class){
return new WeakReference(targetValue);
}else if(this.targetType == SoftReference.class){
return new SoftReference(targetValue);
}
throw new UnsupportedOperationException(StrUtil.format("Unsupport Reference type: {}", this.targetType.getName()));
}
}
package cn.hutool.core.convert.impl;
import java.util.Map;
import cn.hutool.core.convert.AbstractConverter;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
/**
* {@link StackTraceElement} 转换器<br>
* 只支持Map方式转换
*
* @author Looly
* @since 3.0.8
*/
public class StackTraceElementConverter extends AbstractConverter<StackTraceElement> {
private static final long serialVersionUID = 1L;
@Override
protected StackTraceElement convertInternal(Object value) {
if (value instanceof Map) {
final Map<?, ?> map = (Map<?, ?>) value;
final String declaringClass = MapUtil.getStr(map, "className");
final String methodName = MapUtil.getStr(map, "methodName");
final String fileName = MapUtil.getStr(map, "fileName");
final Integer lineNumber = MapUtil.getInt(map, "lineNumber");
return new StackTraceElement(declaringClass, methodName, fileName, ObjectUtil.defaultIfNull(lineNumber, 0));
}
return null;
}
}
package cn.hutool.core.convert.impl;
import cn.hutool.core.convert.AbstractConverter;
import cn.hutool.core.convert.ConvertException;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.XmlUtil;
import java.io.InputStream;
import java.io.Reader;
import java.lang.reflect.Type;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.SQLException;
import java.util.TimeZone;
/**
* 字符串转换器,提供各种对象转换为字符串的逻辑封装
*
* @author Looly
*/
public class StringConverter extends AbstractConverter<String> {
private static final long serialVersionUID = 1L;
@Override
protected String convertInternal(Object value) {
if (value instanceof TimeZone) {
return ((TimeZone) value).getID();
} else if (value instanceof org.w3c.dom.Node) {
return XmlUtil.toStr((org.w3c.dom.Node) value);
} else if (value instanceof Clob) {
return clobToStr((Clob) value);
} else if (value instanceof Blob) {
return blobToStr((Blob) value);
} else if (value instanceof Type) {
return ((Type) value).getTypeName();
}
// 其它情况
return convertToStr(value);
}
/**
* Clob字段值转字符串
*
* @param clob {@link Clob}
* @return 字符串
* @since 5.4.5
*/
private static String clobToStr(Clob clob) {
Reader reader = null;
try {
reader = clob.getCharacterStream();
return IoUtil.read(reader);
} catch (SQLException e) {
throw new ConvertException(e);
} finally {
IoUtil.close(reader);
}
}
/**
* Blob字段值转字符串
*
* @param blob {@link Blob}
* @return 字符串
* @since 5.4.5
*/
private static String blobToStr(Blob blob) {
InputStream in = null;
try {
in = blob.getBinaryStream();
return IoUtil.read(in, CharsetUtil.CHARSET_UTF_8);
} catch (SQLException e) {
throw new ConvertException(e);
} finally {
IoUtil.close(in);
}
}
}
package cn.hutool.core.convert.impl;
import cn.hutool.core.convert.AbstractConverter;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.convert.ConvertException;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.format.GlobalCustomFormat;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import java.time.DayOfWeek;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Month;
import java.time.MonthDay;
import java.time.OffsetDateTime;
import java.time.OffsetTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.chrono.Era;
import java.time.chrono.IsoEra;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAccessor;
import java.util.Calendar;
import java.util.Date;
import java.util.Map;
import java.util.Objects;
/**
* JDK8中新加入的java.time包对象解析转换器<br>
* 支持的对象包括:
*
* <pre>
* java.time.Instant
* java.time.LocalDateTime
* java.time.LocalDate
* java.time.LocalTime
* java.time.ZonedDateTime
* java.time.OffsetDateTime
* java.time.OffsetTime
* </pre>
*
* @author looly
* @since 5.0.0
*/
public class TemporalAccessorConverter extends AbstractConverter<TemporalAccessor> {
private static final long serialVersionUID = 1L;
private final Class<?> targetType;
/**
* 日期格式化
*/
private String format;
/**
* 构造
*
* @param targetType 目标类型
*/
public TemporalAccessorConverter(Class<?> targetType) {
this(targetType, null);
}
/**
* 构造
*
* @param targetType 目标类型
* @param format 日期格式
*/
public TemporalAccessorConverter(Class<?> targetType, String format) {
this.targetType = targetType;
this.format = format;
}
/**
* 获取日期格式
*
* @return 设置日期格式
*/
public String getFormat() {
return format;
}
/**
* 设置日期格式
*
* @param format 日期格式
*/
public void setFormat(String format) {
this.format = format;
}
@SuppressWarnings("unchecked")
@Override
public Class<TemporalAccessor> getTargetType() {
return (Class<TemporalAccessor>) this.targetType;
}
@Override
protected TemporalAccessor convertInternal(Object value) {
if (value instanceof Number) {
return parseFromLong(((Number) value).longValue());
} else if (value instanceof TemporalAccessor) {
return parseFromTemporalAccessor((TemporalAccessor) value);
} else if (value instanceof Date) {
final DateTime dateTime = DateUtil.date((Date) value);
return parseFromInstant(dateTime.toInstant(), dateTime.getZoneId());
} else if (value instanceof Calendar) {
final Calendar calendar = (Calendar) value;
return parseFromInstant(calendar.toInstant(), calendar.getTimeZone().toZoneId());
} else if (value instanceof Map) {
final Map<?, ?> map = (Map<?, ?>) value;
if (LocalDate.class.equals(this.targetType)) {
return LocalDate.of(Convert.toInt(map.get("year")), Convert.toInt(map.get("month")), Convert.toInt(map.get("day")));
} else if (LocalDateTime.class.equals(this.targetType)) {
return LocalDateTime.of(Convert.toInt(map.get("year")), Convert.toInt(map.get("month")), Convert.toInt(map.get("day")),
Convert.toInt(map.get("hour")), Convert.toInt(map.get("minute")), Convert.toInt(map.get("second")), Convert.toInt(map.get("second")));
} else if (LocalTime.class.equals(this.targetType)) {
return LocalTime.of(Convert.toInt(map.get("hour")), Convert.toInt(map.get("minute")), Convert.toInt(map.get("second")), Convert.toInt(map.get("nano")));
}
throw new ConvertException("Unsupported type: [{}] from map: [{}]", this.targetType, map);
} else {
return parseFromCharSequence(convertToStr(value));
}
}
/**
* 通过反射从字符串转java.time中的对象
*
* @param value 字符串值
* @return 日期对象
*/
private TemporalAccessor parseFromCharSequence(CharSequence value) {
if (StrUtil.isBlank(value)) {
return null;
}
if(DayOfWeek.class.equals(this.targetType)){
return DayOfWeek.valueOf(StrUtil.toString(value));
} else if(Month.class.equals(this.targetType)){
return Month.valueOf(StrUtil.toString(value));
} else if(Era.class.equals(this.targetType)){
return IsoEra.valueOf(StrUtil.toString(value));
} else if(MonthDay.class.equals(this.targetType)){
return MonthDay.parse(value);
}
final Instant instant;
ZoneId zoneId;
if (null != this.format) {
final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(this.format);
instant = formatter.parse(value, Instant::from);
zoneId = formatter.getZone();
} else {
final DateTime dateTime = DateUtil.parse(value);
instant = Objects.requireNonNull(dateTime).toInstant();
zoneId = dateTime.getZoneId();
}
return parseFromInstant(instant, zoneId);
}
/**
* 将Long型时间戳转换为java.time中的对象
*
* @param time 时间戳
* @return java.time中的对象
*/
private TemporalAccessor parseFromLong(Long time) {
if(DayOfWeek.class.equals(this.targetType)){
return DayOfWeek.of(Math.toIntExact(time));
} else if(Month.class.equals(this.targetType)){
return Month.of(Math.toIntExact(time));
} else if(Era.class.equals(this.targetType)){
return IsoEra.of(Math.toIntExact(time));
}
final Instant instant;
if(GlobalCustomFormat.FORMAT_SECONDS.equals(this.format)){
// https://gitee.com/dromara/hutool/issues/I6IS5B
// Unix时间戳
instant = Instant.ofEpochSecond(time);
}else{
instant = Instant.ofEpochMilli(time);
}
return parseFromInstant(instant, null);
}
/**
* 将TemporalAccessor型时间戳转换为java.time中的对象
*
* @param temporalAccessor TemporalAccessor对象
* @return java.time中的对象
*/
private TemporalAccessor parseFromTemporalAccessor(TemporalAccessor temporalAccessor) {
if(DayOfWeek.class.equals(this.targetType)){
return DayOfWeek.from(temporalAccessor);
} else if(Month.class.equals(this.targetType)){
return Month.from(temporalAccessor);
} else if(MonthDay.class.equals(this.targetType)){
return MonthDay.from(temporalAccessor);
}
TemporalAccessor result = null;
if (temporalAccessor instanceof LocalDateTime) {
result = parseFromLocalDateTime((LocalDateTime) temporalAccessor);
} else if (temporalAccessor instanceof ZonedDateTime) {
result = parseFromZonedDateTime((ZonedDateTime) temporalAccessor);
}
if (null == result) {
result = parseFromInstant(DateUtil.toInstant(temporalAccessor), null);
}
return result;
}
/**
* 将TemporalAccessor型时间戳转换为java.time中的对象
*
* @param localDateTime {@link LocalDateTime}对象
* @return java.time中的对象
*/
private TemporalAccessor parseFromLocalDateTime(LocalDateTime localDateTime) {
if (Instant.class.equals(this.targetType)) {
return DateUtil.toInstant(localDateTime);
}
if (LocalDate.class.equals(this.targetType)) {
return localDateTime.toLocalDate();
}
if (LocalTime.class.equals(this.targetType)) {
return localDateTime.toLocalTime();
}
if (ZonedDateTime.class.equals(this.targetType)) {
return localDateTime.atZone(ZoneId.systemDefault());
}
if (OffsetDateTime.class.equals(this.targetType)) {
return localDateTime.atZone(ZoneId.systemDefault()).toOffsetDateTime();
}
if (OffsetTime.class.equals(this.targetType)) {
return localDateTime.atZone(ZoneId.systemDefault()).toOffsetDateTime().toOffsetTime();
}
return null;
}
/**
* 将TemporalAccessor型时间戳转换为java.time中的对象
*
* @param zonedDateTime {@link ZonedDateTime}对象
* @return java.time中的对象
*/
private TemporalAccessor parseFromZonedDateTime(ZonedDateTime zonedDateTime) {
if (Instant.class.equals(this.targetType)) {
return DateUtil.toInstant(zonedDateTime);
}
if (LocalDateTime.class.equals(this.targetType)) {
return zonedDateTime.toLocalDateTime();
}
if (LocalDate.class.equals(this.targetType)) {
return zonedDateTime.toLocalDate();
}
if (LocalTime.class.equals(this.targetType)) {
return zonedDateTime.toLocalTime();
}
if (OffsetDateTime.class.equals(this.targetType)) {
return zonedDateTime.toOffsetDateTime();
}
if (OffsetTime.class.equals(this.targetType)) {
return zonedDateTime.toOffsetDateTime().toOffsetTime();
}
return null;
}
/**
* 将TemporalAccessor型时间戳转换为java.time中的对象
*
* @param instant {@link Instant}对象
* @param zoneId 时区ID,null表示当前系统默认的时区
* @return java.time中的对象
*/
private TemporalAccessor parseFromInstant(Instant instant, ZoneId zoneId) {
if (Instant.class.equals(this.targetType)) {
return instant;
}
zoneId = ObjectUtil.defaultIfNull(zoneId, ZoneId::systemDefault);
TemporalAccessor result = null;
if (LocalDateTime.class.equals(this.targetType)) {
result = LocalDateTime.ofInstant(instant, zoneId);
} else if (LocalDate.class.equals(this.targetType)) {
result = instant.atZone(zoneId).toLocalDate();
} else if (LocalTime.class.equals(this.targetType)) {
result = instant.atZone(zoneId).toLocalTime();
} else if (ZonedDateTime.class.equals(this.targetType)) {
result = instant.atZone(zoneId);
} else if (OffsetDateTime.class.equals(this.targetType)) {
result = OffsetDateTime.ofInstant(instant, zoneId);
} else if (OffsetTime.class.equals(this.targetType)) {
result = OffsetTime.ofInstant(instant, zoneId);
}
return result;
}
}
package cn.hutool.core.convert.impl;
import java.util.TimeZone;
import cn.hutool.core.convert.AbstractConverter;
/**
* TimeZone转换器
* @author Looly
*
*/
public class TimeZoneConverter extends AbstractConverter<TimeZone>{
private static final long serialVersionUID = 1L;
@Override
protected TimeZone convertInternal(Object value) {
return TimeZone.getTimeZone(convertToStr(value));
}
}
package cn.hutool.core.convert.impl;
import java.io.File;
import java.net.URI;
import java.net.URL;
import cn.hutool.core.convert.AbstractConverter;
/**
* URI对象转换器
* @author Looly
*
*/
public class URIConverter extends AbstractConverter<URI>{
private static final long serialVersionUID = 1L;
@Override
protected URI convertInternal(Object value) {
try {
if(value instanceof File){
return ((File)value).toURI();
}
if(value instanceof URL){
return ((URL)value).toURI();
}
return new URI(convertToStr(value));
} catch (Exception e) {
// Ignore Exception
}
return null;
}
}
package cn.hutool.core.convert.impl;
import java.io.File;
import java.net.URI;
import java.net.URL;
import cn.hutool.core.convert.AbstractConverter;
/**
* URL对象转换器
* @author Looly
*
*/
public class URLConverter extends AbstractConverter<URL>{
private static final long serialVersionUID = 1L;
@Override
protected URL convertInternal(Object value) {
try {
if(value instanceof File){
return ((File)value).toURI().toURL();
}
if(value instanceof URI){
return ((URI)value).toURL();
}
return new URL(convertToStr(value));
} catch (Exception e) {
// Ignore Exception
}
return null;
}
}
package cn.hutool.core.convert.impl;
import java.util.UUID;
import cn.hutool.core.convert.AbstractConverter;
/**
* UUID对象转换器转换器
*
* @author Looly
* @since 4.0.10
*
*/
public class UUIDConverter extends AbstractConverter<UUID> {
private static final long serialVersionUID = 1L;
@Override
protected UUID convertInternal(Object value) {
return UUID.fromString(convertToStr(value));
}
}
/**
* 各种类型转换的实现类,其都为Converter接口的实现,用于将未知的Object类型转换为指定类型
*
* @author looly
*
*/
package cn.hutool.core.convert.impl;
\ No newline at end of file
/**
* 万能类型转换器以及各种类型转换的实现类,其中Convert为转换器入口,提供各种toXXX方法和convert方法
*
* @author looly
*
*/
package cn.hutool.core.convert;
\ No newline at end of file
package cn.hutool.core.date;
import cn.hutool.core.util.StrUtil;
import java.io.Serializable;
/**
* 时长格式化器,用于格式化输出两个日期相差的时长<br>
* 根据{@link Level}不同,调用{@link #format()}方法后返回类似于:
* <ul>
* <li>XX小时XX分XX秒</li>
* <li>XX天XX小时</li>
* <li>XX月XX天XX小时</li>
* </ul>
*
* @author Looly
*/
public class BetweenFormatter implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 时长毫秒数
*/
private long betweenMs;
/**
* 格式化级别
*/
private Level level;
/**
* 格式化级别的最大个数
*/
private final int levelMaxCount;
/**
* 构造
*
* @param betweenMs 日期间隔
* @param level 级别,按照天、小时、分、秒、毫秒分为5个等级,根据传入等级,格式化到相应级别
*/
public BetweenFormatter(long betweenMs, Level level) {
this(betweenMs, level, 0);
}
/**
* 构造
*
* @param betweenMs 日期间隔
* @param level 级别,按照天、小时、分、秒、毫秒分为5个等级,根据传入等级,格式化到相应级别
* @param levelMaxCount 格式化级别的最大个数,假如级别个数为1,但是级别到秒,那只显示一个级别
*/
public BetweenFormatter(long betweenMs, Level level, int levelMaxCount) {
this.betweenMs = betweenMs;
this.level = level;
this.levelMaxCount = levelMaxCount;
}
/**
* 格式化日期间隔输出<br>
*
* @return 格式化后的字符串
*/
public String format() {
final StringBuilder sb = new StringBuilder();
if (betweenMs > 0) {
long day = betweenMs / DateUnit.DAY.getMillis();
long hour = betweenMs / DateUnit.HOUR.getMillis() - day * 24;
long minute = betweenMs / DateUnit.MINUTE.getMillis() - day * 24 * 60 - hour * 60;
final long BetweenOfSecond = ((day * 24 + hour) * 60 + minute) * 60;
long second = betweenMs / DateUnit.SECOND.getMillis() - BetweenOfSecond;
long millisecond = betweenMs - (BetweenOfSecond + second) * 1000;
final int level = this.level.ordinal();
int levelCount = 0;
if (isLevelCountValid(levelCount) && 0 != day && level >= Level.DAY.ordinal()) {
sb.append(day).append(Level.DAY.name);
levelCount++;
}
if (isLevelCountValid(levelCount) && 0 != hour && level >= Level.HOUR.ordinal()) {
sb.append(hour).append(Level.HOUR.name);
levelCount++;
}
if (isLevelCountValid(levelCount) && 0 != minute && level >= Level.MINUTE.ordinal()) {
sb.append(minute).append(Level.MINUTE.name);
levelCount++;
}
if (isLevelCountValid(levelCount) && 0 != second && level >= Level.SECOND.ordinal()) {
sb.append(second).append(Level.SECOND.name);
levelCount++;
}
if (isLevelCountValid(levelCount) && 0 != millisecond && level >= Level.MILLISECOND.ordinal()) {
sb.append(millisecond).append(Level.MILLISECOND.name);
// levelCount++;
}
}
if (StrUtil.isEmpty(sb)) {
sb.append(0).append(this.level.name);
}
return sb.toString();
}
/**
* 获得 时长毫秒数
*
* @return 时长毫秒数
*/
public long getBetweenMs() {
return betweenMs;
}
/**
* 设置 时长毫秒数
*
* @param betweenMs 时长毫秒数
*/
public void setBetweenMs(long betweenMs) {
this.betweenMs = betweenMs;
}
/**
* 获得 格式化级别
*
* @return 格式化级别
*/
public Level getLevel() {
return level;
}
/**
* 设置格式化级别
*
* @param level 格式化级别
*/
public void setLevel(Level level) {
this.level = level;
}
/**
* 格式化等级枚举
*
* @author Looly
*/
public enum Level {
/**
* 天
*/
DAY("天"),
/**
* 小时
*/
HOUR("小时"),
/**
* 分钟
*/
MINUTE("分"),
/**
* 秒
*/
SECOND("秒"),
/**
* 毫秒
*/
MILLISECOND("毫秒");
/**
* 级别名称
*/
private final String name;
/**
* 构造
*
* @param name 级别名称
*/
Level(String name) {
this.name = name;
}
/**
* 获取级别名称
*
* @return 级别名称
*/
public String getName() {
return this.name;
}
}
@Override
public String toString() {
return format();
}
/**
* 等级数量是否有效<br>
* 有效的定义是:levelMaxCount大于0(被设置),当前等级数量没有超过这个最大值
*
* @param levelCount 登记数量
* @return 是否有效
*/
private boolean isLevelCountValid(int levelCount) {
return this.levelMaxCount <= 0 || levelCount < this.levelMaxCount;
}
}
package cn.hutool.core.date;
import cn.hutool.core.comparator.CompareUtil;
import cn.hutool.core.convert.NumberChineseFormatter;
import cn.hutool.core.date.format.DateParser;
import cn.hutool.core.date.format.FastDateParser;
import cn.hutool.core.date.format.GlobalCustomFormat;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import java.text.ParsePosition;
import java.time.Instant;
import java.time.LocalDateTime;
import java.util.Calendar;
import java.util.Date;
import java.util.LinkedHashSet;
import java.util.Locale;
import java.util.TimeZone;
/**
* 针对{@link Calendar} 对象封装工具类
*
* @author looly
* @since 5.3.0
*/
public class CalendarUtil {
/**
* 创建Calendar对象,时间为默认时区的当前时间
*
* @return Calendar对象
* @since 4.6.6
*/
public static Calendar calendar() {
return Calendar.getInstance();
}
/**
* 转换为Calendar对象
*
* @param date 日期对象
* @return Calendar对象
*/
public static Calendar calendar(Date date) {
if (date instanceof DateTime) {
return ((DateTime) date).toCalendar();
} else {
return calendar(date.getTime());
}
}
/**
* 转换为Calendar对象,使用当前默认时区
*
* @param millis 时间戳
* @return Calendar对象
*/
public static Calendar calendar(long millis) {
return calendar(millis, TimeZone.getDefault());
}
/**
* 转换为Calendar对象
*
* @param millis 时间戳
* @param timeZone 时区
* @return Calendar对象
* @since 5.7.22
*/
public static Calendar calendar(long millis, TimeZone timeZone) {
final Calendar cal = Calendar.getInstance(timeZone);
cal.setTimeInMillis(millis);
return cal;
}
/**
* 是否为上午
*
* @param calendar {@link Calendar}
* @return 是否为上午
*/
public static boolean isAM(Calendar calendar) {
return Calendar.AM == calendar.get(Calendar.AM_PM);
}
/**
* 是否为下午
*
* @param calendar {@link Calendar}
* @return 是否为下午
*/
public static boolean isPM(Calendar calendar) {
return Calendar.PM == calendar.get(Calendar.AM_PM);
}
/**
* 修改日期为某个时间字段起始时间
*
* @param calendar {@link Calendar}
* @param dateField 保留到的时间字段,如定义为 {@link DateField#SECOND},表示这个字段不变,这个字段以下字段全部归0
* @return 原{@link Calendar}
*/
public static Calendar truncate(Calendar calendar, DateField dateField) {
return DateModifier.modify(calendar, dateField.getValue(), DateModifier.ModifyType.TRUNCATE);
}
/**
* 修改日期为某个时间字段四舍五入时间
*
* @param calendar {@link Calendar}
* @param dateField 时间字段
* @return 原{@link Calendar}
*/
public static Calendar round(Calendar calendar, DateField dateField) {
return DateModifier.modify(calendar, dateField.getValue(), DateModifier.ModifyType.ROUND);
}
/**
* 修改日期为某个时间字段结束时间
*
* @param calendar {@link Calendar}
* @param dateField 保留到的时间字段,如定义为 {@link DateField#SECOND},表示这个字段不变,这个字段以下字段全部取最大值
* @return 原{@link Calendar}
*/
public static Calendar ceiling(Calendar calendar, DateField dateField) {
return DateModifier.modify(calendar, dateField.getValue(), DateModifier.ModifyType.CEILING);
}
/**
* 修改日期为某个时间字段结束时间<br>
* 可选是否归零毫秒。
*
* <p>
* 有时候由于毫秒部分必须为0(如MySQL数据库中),因此在此加上选项。
* </p>
*
* @param calendar {@link Calendar}
* @param dateField 时间字段
* @param truncateMillisecond 是否毫秒归零
* @return 原{@link Calendar}
*/
public static Calendar ceiling(Calendar calendar, DateField dateField, boolean truncateMillisecond) {
return DateModifier.modify(calendar, dateField.getValue(), DateModifier.ModifyType.CEILING, truncateMillisecond);
}
/**
* 修改秒级别的开始时间,即忽略毫秒部分
*
* @param calendar 日期 {@link Calendar}
* @return {@link Calendar}
* @since 4.6.2
*/
public static Calendar beginOfSecond(Calendar calendar) {
return truncate(calendar, DateField.SECOND);
}
/**
* 修改秒级别的结束时间,即毫秒设置为999
*
* @param calendar 日期 {@link Calendar}
* @return {@link Calendar}
* @since 4.6.2
*/
public static Calendar endOfSecond(Calendar calendar) {
return ceiling(calendar, DateField.SECOND);
}
/**
* 修改某小时的开始时间
*
* @param calendar 日期 {@link Calendar}
* @return {@link Calendar}
*/
public static Calendar beginOfHour(Calendar calendar) {
return truncate(calendar, DateField.HOUR_OF_DAY);
}
/**
* 修改某小时的结束时间
*
* @param calendar 日期 {@link Calendar}
* @return {@link Calendar}
*/
public static Calendar endOfHour(Calendar calendar) {
return ceiling(calendar, DateField.HOUR_OF_DAY);
}
/**
* 修改某分钟的开始时间
*
* @param calendar 日期 {@link Calendar}
* @return {@link Calendar}
*/
public static Calendar beginOfMinute(Calendar calendar) {
return truncate(calendar, DateField.MINUTE);
}
/**
* 修改某分钟的结束时间
*
* @param calendar 日期 {@link Calendar}
* @return {@link Calendar}
*/
public static Calendar endOfMinute(Calendar calendar) {
return ceiling(calendar, DateField.MINUTE);
}
/**
* 修改某天的开始时间
*
* @param calendar 日期 {@link Calendar}
* @return {@link Calendar}
*/
public static Calendar beginOfDay(Calendar calendar) {
return truncate(calendar, DateField.DAY_OF_MONTH);
}
/**
* 修改某天的结束时间
*
* @param calendar 日期 {@link Calendar}
* @return {@link Calendar}
*/
public static Calendar endOfDay(Calendar calendar) {
return ceiling(calendar, DateField.DAY_OF_MONTH);
}
/**
* 修改给定日期当前周的开始时间,周一定为一周的开始时间
*
* @param calendar 日期 {@link Calendar}
* @return {@link Calendar}
*/
public static Calendar beginOfWeek(Calendar calendar) {
return beginOfWeek(calendar, true);
}
/**
* 修改给定日期当前周的开始时间
*
* @param calendar 日期 {@link Calendar}
* @param isMondayAsFirstDay 是否周一做为一周的第一天(false表示周日做为第一天)
* @return {@link Calendar}
* @since 3.1.2
*/
public static Calendar beginOfWeek(Calendar calendar, boolean isMondayAsFirstDay) {
calendar.setFirstDayOfWeek(isMondayAsFirstDay ? Calendar.MONDAY : Calendar.SUNDAY);
// WEEK_OF_MONTH为上限的字段(不包括),实际调整的为DAY_OF_MONTH
return truncate(calendar, DateField.WEEK_OF_MONTH);
}
/**
* 修改某周的结束时间,周日定为一周的结束
*
* @param calendar 日期 {@link Calendar}
* @return {@link Calendar}
*/
public static Calendar endOfWeek(Calendar calendar) {
return endOfWeek(calendar, true);
}
/**
* 修改某周的结束时间
*
* @param calendar 日期 {@link Calendar}
* @param isSundayAsLastDay 是否周日做为一周的最后一天(false表示周六做为最后一天)
* @return {@link Calendar}
*/
public static Calendar endOfWeek(Calendar calendar, boolean isSundayAsLastDay) {
calendar.setFirstDayOfWeek(isSundayAsLastDay ? Calendar.MONDAY : Calendar.SUNDAY);
// WEEK_OF_MONTH为上限的字段(不包括),实际调整的为DAY_OF_MONTH
return ceiling(calendar, DateField.WEEK_OF_MONTH);
}
/**
* 修改某月的开始时间
*
* @param calendar 日期 {@link Calendar}
* @return {@link Calendar}
*/
public static Calendar beginOfMonth(Calendar calendar) {
return truncate(calendar, DateField.MONTH);
}
/**
* 修改某月的结束时间
*
* @param calendar 日期 {@link Calendar}
* @return {@link Calendar}
*/
public static Calendar endOfMonth(Calendar calendar) {
return ceiling(calendar, DateField.MONTH);
}
/**
* 修改某季度的开始时间
*
* @param calendar 日期 {@link Calendar}
* @return {@link Calendar}
* @since 4.1.0
*/
public static Calendar beginOfQuarter(Calendar calendar) {
//noinspection MagicConstant
calendar.set(Calendar.MONTH, calendar.get(DateField.MONTH.getValue()) / 3 * 3);
calendar.set(Calendar.DAY_OF_MONTH, 1);
return beginOfDay(calendar);
}
/**
* 获取某季度的结束时间
*
* @param calendar 日期 {@link Calendar}
* @return {@link Calendar}
* @since 4.1.0
*/
@SuppressWarnings({"MagicConstant", "ConstantConditions"})
public static Calendar endOfQuarter(Calendar calendar) {
final int year = calendar.get(Calendar.YEAR);
final int month = calendar.get(DateField.MONTH.getValue()) / 3 * 3 + 2;
final Calendar resultCal = Calendar.getInstance(calendar.getTimeZone());
resultCal.set(year, month, Month.of(month).getLastDay(DateUtil.isLeapYear(year)));
return endOfDay(resultCal);
}
/**
* 修改某年的开始时间
*
* @param calendar 日期 {@link Calendar}
* @return {@link Calendar}
*/
public static Calendar beginOfYear(Calendar calendar) {
return truncate(calendar, DateField.YEAR);
}
/**
* 修改某年的结束时间
*
* @param calendar 日期 {@link Calendar}
* @return {@link Calendar}
*/
public static Calendar endOfYear(Calendar calendar) {
return ceiling(calendar, DateField.YEAR);
}
/**
* 比较两个日期是否为同一天
*
* @param cal1 日期1
* @param cal2 日期2
* @return 是否为同一天
*/
public static boolean isSameDay(Calendar cal1, Calendar cal2) {
if (cal1 == null || cal2 == null) {
throw new IllegalArgumentException("The date must not be null");
}
return cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR) && //
cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) && //
cal1.get(Calendar.ERA) == cal2.get(Calendar.ERA);
}
/**
* 比较两个日期是否为同一周
*
* @param cal1 日期1
* @param cal2 日期2
* @param isMon 是否为周一。国内第一天为星期一,国外第一天为星期日
* @return 是否为同一周
* @since 5.7.21
*/
public static boolean isSameWeek(Calendar cal1, Calendar cal2, boolean isMon) {
if (cal1 == null || cal2 == null) {
throw new IllegalArgumentException("The date must not be null");
}
// 防止比较前修改原始Calendar对象
cal1 = (Calendar) cal1.clone();
cal2 = (Calendar) cal2.clone();
// 把所传日期设置为其当前周的第一天
// 比较设置后的两个日期是否是同一天:true 代表同一周
if (isMon) {
cal1.setFirstDayOfWeek(Calendar.MONDAY);
cal1.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
cal2.setFirstDayOfWeek(Calendar.MONDAY);
cal2.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
} else {
cal1.setFirstDayOfWeek(Calendar.SUNDAY);
cal1.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
cal2.setFirstDayOfWeek(Calendar.SUNDAY);
cal2.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
}
return isSameDay(cal1, cal2);
}
/**
* 比较两个日期是否为同一月<br>
* 同一个月的意思是:ERA(公元)、year(年)、month(月)都一致。
*
* @param cal1 日期1
* @param cal2 日期2
* @return 是否为同一月
* @since 5.4.1
*/
public static boolean isSameMonth(Calendar cal1, Calendar cal2) {
if (cal1 == null || cal2 == null) {
throw new IllegalArgumentException("The date must not be null");
}
return cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) && //
cal1.get(Calendar.MONTH) == cal2.get(Calendar.MONTH) &&
// issue#3011@Github
cal1.get(Calendar.ERA) == cal2.get(Calendar.ERA);
}
/**
* <p>检查两个Calendar时间戳是否相同。</p>
*
* <p>此方法检查两个Calendar的毫秒数时间戳是否相同。</p>
*
* @param date1 时间1
* @param date2 时间2
* @return 两个Calendar时间戳是否相同。如果两个时间都为{@code null}返回true,否则有{@code null}返回false
* @since 5.3.11
*/
public static boolean isSameInstant(Calendar date1, Calendar date2) {
if (null == date1) {
return null == date2;
}
if (null == date2) {
return false;
}
return date1.getTimeInMillis() == date2.getTimeInMillis();
}
/**
* 获得指定日期区间内的年份和季度<br>
*
* @param startDate 起始日期(包含)
* @param endDate 结束日期(包含)
* @return 季度列表 ,元素类似于 20132
* @since 4.1.15
*/
public static LinkedHashSet<String> yearAndQuarter(long startDate, long endDate) {
LinkedHashSet<String> quarters = new LinkedHashSet<>();
final Calendar cal = calendar(startDate);
while (startDate <= endDate) {
// 如果开始时间超出结束时间,让结束时间为开始时间,处理完后结束循环
quarters.add(yearAndQuarter(cal));
cal.add(Calendar.MONTH, 3);
startDate = cal.getTimeInMillis();
}
return quarters;
}
/**
* 获得指定日期年份和季度<br>
* 格式:[20131]表示2013年第一季度
*
* @param cal 日期
* @return 年和季度,格式类似于20131
*/
public static String yearAndQuarter(Calendar cal) {
return StrUtil.builder().append(cal.get(Calendar.YEAR)).append(cal.get(Calendar.MONTH) / 3 + 1).toString();
}
/**
* 获取指定日期字段的最小值,例如分钟的最小值是0
*
* @param calendar {@link Calendar}
* @param dateField {@link DateField}
* @return 字段最小值
* @see Calendar#getActualMinimum(int)
* @since 5.4.2
*/
public static int getBeginValue(Calendar calendar, DateField dateField) {
return getBeginValue(calendar, dateField.getValue());
}
/**
* 获取指定日期字段的最小值,例如分钟的最小值是0
*
* @param calendar {@link Calendar}
* @param dateField {@link DateField}
* @return 字段最小值
* @see Calendar#getActualMinimum(int)
* @since 4.5.7
*/
public static int getBeginValue(Calendar calendar, int dateField) {
if (Calendar.DAY_OF_WEEK == dateField) {
return calendar.getFirstDayOfWeek();
}
return calendar.getActualMinimum(dateField);
}
/**
* 获取指定日期字段的最大值,例如分钟的最大值是59
*
* @param calendar {@link Calendar}
* @param dateField {@link DateField}
* @return 字段最大值
* @see Calendar#getActualMaximum(int)
* @since 5.4.2
*/
public static int getEndValue(Calendar calendar, DateField dateField) {
return getEndValue(calendar, dateField.getValue());
}
/**
* 获取指定日期字段的最大值,例如分钟的最大值是59
*
* @param calendar {@link Calendar}
* @param dateField {@link DateField}
* @return 字段最大值
* @see Calendar#getActualMaximum(int)
* @since 4.5.7
*/
public static int getEndValue(Calendar calendar, int dateField) {
if (Calendar.DAY_OF_WEEK == dateField) {
return (calendar.getFirstDayOfWeek() + 6) % 7;
}
return calendar.getActualMaximum(dateField);
}
/**
* Calendar{@link Instant}对象
*
* @param calendar Date对象
* @return {@link Instant}对象
* @since 5.0.5
*/
public static Instant toInstant(Calendar calendar) {
return null == calendar ? null : calendar.toInstant();
}
/**
* {@link Calendar} 转换为 {@link LocalDateTime},使用系统默认时区
*
* @param calendar {@link Calendar}
* @return {@link LocalDateTime}
* @since 5.0.5
*/
public static LocalDateTime toLocalDateTime(Calendar calendar) {
return LocalDateTime.ofInstant(calendar.toInstant(), calendar.getTimeZone().toZoneId());
}
/**
* {@code null}安全的{@link Calendar}比较,{@code null}小于任何日期
*
* @param calendar1 日期1
* @param calendar2 日期2
* @return 比较结果,如果calendar1 &lt; calendar2,返回数小于0,calendar1==calendar2返回0,calendar1 &gt; calendar2 大于0
* @since 4.6.2
*/
public static int compare(Calendar calendar1, Calendar calendar2) {
return CompareUtil.compare(calendar1, calendar2);
}
/**
* 计算相对于dateToCompare的年龄,长用于计算指定生日在某年的年龄
*
* @param birthday 生日
* @param dateToCompare 需要对比的日期
* @return 年龄
*/
public static int age(Calendar birthday, Calendar dateToCompare) {
return age(birthday.getTimeInMillis(), dateToCompare.getTimeInMillis());
}
/**
* 将指定Calendar时间格式化为纯中文形式,比如:
*
* <pre>
* 2018-02-24 12:13:14 转换为 二〇一八年二月二十四日(withTime为false)
* 2018-02-24 12:13:14 转换为 二〇一八年二月二十四日十二时十三分十四秒(withTime为true)
* </pre>
*
* @param calendar {@link Calendar}
* @param withTime 是否包含时间部分
* @return 格式化后的字符串
* @since 5.3.9
*/
public static String formatChineseDate(Calendar calendar, boolean withTime) {
final StringBuilder result = StrUtil.builder();
// 年
final String year = String.valueOf(calendar.get(Calendar.YEAR));
final int length = year.length();
for (int i = 0; i < length; i++) {
result.append(NumberChineseFormatter.numberCharToChinese(year.charAt(i), false));
}
result.append('年');
// 月
int month = calendar.get(Calendar.MONTH) + 1;
result.append(NumberChineseFormatter.formatThousand(month, false));
result.append('月');
// 日
int day = calendar.get(Calendar.DAY_OF_MONTH);
result.append(NumberChineseFormatter.formatThousand(day, false));
result.append('日');
// 只替换年月日,时分秒中零不需要替换
String temp = result.toString().replace('零', '〇');
result.delete(0, result.length());
result.append(temp);
if (withTime) {
// 时
int hour = calendar.get(Calendar.HOUR_OF_DAY);
result.append(NumberChineseFormatter.formatThousand(hour, false));
result.append('时');
// 分
int minute = calendar.get(Calendar.MINUTE);
result.append(NumberChineseFormatter.formatThousand(minute, false));
result.append('分');
// 秒
int second = calendar.get(Calendar.SECOND);
result.append(NumberChineseFormatter.formatThousand(second, false));
result.append('秒');
}
return result.toString();
}
/**
* 计算相对于dateToCompare的年龄,常用于计算指定生日在某年的年龄
*
* @param birthday 生日
* @param dateToCompare 需要对比的日期
* @return 年龄
*/
protected static int age(long birthday, long dateToCompare) {
if (birthday > dateToCompare) {
throw new IllegalArgumentException("Birthday is after dateToCompare!");
}
final Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(dateToCompare);
final int year = cal.get(Calendar.YEAR);
final int month = cal.get(Calendar.MONTH);
final int dayOfMonth = cal.get(Calendar.DAY_OF_MONTH);
final boolean isLastDayOfMonth = dayOfMonth == cal.getActualMaximum(Calendar.DAY_OF_MONTH);
cal.setTimeInMillis(birthday);
int age = year - cal.get(Calendar.YEAR);
final int monthBirth = cal.get(Calendar.MONTH);
//当前日期,则为0岁
if (age == 0){
return 0;
} else if (month == monthBirth) {
final int dayOfMonthBirth = cal.get(Calendar.DAY_OF_MONTH);
final boolean isLastDayOfMonthBirth = dayOfMonthBirth == cal.getActualMaximum(Calendar.DAY_OF_MONTH);
if ((false == isLastDayOfMonth || false == isLastDayOfMonthBirth) && dayOfMonth <= dayOfMonthBirth) {
// 如果生日在当月,但是未超过生日当天的日期,年龄减一
age--;
}
} else if (month < monthBirth) {
// 如果当前月份未达到生日的月份,年龄计算减一
age--;
}
return age;
}
/**
* 通过给定的日期格式解析日期时间字符串。<br>
* 传入的日期格式会逐个尝试,直到解析成功,返回{@link Calendar}对象,否则抛出{@link DateException}异常。
* 方法来自:Apache Commons-Lang3
*
* @param str 日期时间字符串,非空
* @param parsePatterns 需要尝试的日期时间格式数组,非空, 见SimpleDateFormat
* @return 解析后的Calendar
* @throws IllegalArgumentException if the date string or pattern array is null
* @throws DateException if none of the date patterns were suitable
* @since 5.3.11
*/
public static Calendar parseByPatterns(String str, String... parsePatterns) throws DateException {
return parseByPatterns(str, null, parsePatterns);
}
/**
* 通过给定的日期格式解析日期时间字符串。<br>
* 传入的日期格式会逐个尝试,直到解析成功,返回{@link Calendar}对象,否则抛出{@link DateException}异常。
* 方法来自:Apache Commons-Lang3
*
* @param str 日期时间字符串,非空
* @param locale 地区,当为{@code null}时使用{@link Locale#getDefault()}
* @param parsePatterns 需要尝试的日期时间格式数组,非空, 见SimpleDateFormat
* @return 解析后的Calendar
* @throws IllegalArgumentException if the date string or pattern array is null
* @throws DateException if none of the date patterns were suitable
* @since 5.3.11
*/
public static Calendar parseByPatterns(String str, Locale locale, String... parsePatterns) throws DateException {
return parseByPatterns(str, locale, true, parsePatterns);
}
/**
* 通过给定的日期格式解析日期时间字符串。<br>
* 传入的日期格式会逐个尝试,直到解析成功,返回{@link Calendar}对象,否则抛出{@link DateException}异常。
* 方法来自:Apache Commons-Lang3
*
* @param str 日期时间字符串,非空
* @param locale 地区,当为{@code null}时使用{@link Locale#getDefault()}
* @param lenient 日期时间解析是否使用严格模式
* @param parsePatterns 需要尝试的日期时间格式数组,非空, 见SimpleDateFormat
* @return 解析后的Calendar
* @throws IllegalArgumentException if the date string or pattern array is null
* @throws DateException if none of the date patterns were suitable
* @see java.util.Calendar#isLenient()
* @since 5.3.11
*/
public static Calendar parseByPatterns(String str, Locale locale, boolean lenient, String... parsePatterns) throws DateException {
if (str == null || parsePatterns == null) {
throw new IllegalArgumentException("Date and Patterns must not be null");
}
final TimeZone tz = TimeZone.getDefault();
final Locale lcl = ObjectUtil.defaultIfNull(locale, Locale.getDefault());
final ParsePosition pos = new ParsePosition(0);
final Calendar calendar = Calendar.getInstance(tz, lcl);
calendar.setLenient(lenient);
for (final String parsePattern : parsePatterns) {
if (GlobalCustomFormat.isCustomFormat(parsePattern)) {
final Date parse = GlobalCustomFormat.parse(str, parsePattern);
if (null == parse) {
continue;
}
calendar.setTime(parse);
return calendar;
}
final FastDateParser fdp = new FastDateParser(parsePattern, tz, lcl);
calendar.clear();
try {
if (fdp.parse(str, pos, calendar) && pos.getIndex() == str.length()) {
return calendar;
}
} catch (final IllegalArgumentException ignore) {
// leniency is preventing calendar from being set
}
pos.setIndex(0);
}
throw new DateException("Unable to parse the date: {}", str);
}
/**
* 使用指定{@link DateParser}解析字符串为{@link Calendar}
*
* @param str 日期字符串
* @param lenient 是否宽容模式
* @param parser {@link DateParser}
* @return 解析后的 {@link Calendar},解析失败返回{@code null}
* @since 5.7.14
*/
public static Calendar parse(CharSequence str, boolean lenient, DateParser parser) {
final Calendar calendar = Calendar.getInstance(parser.getTimeZone(), parser.getLocale());
calendar.clear();
calendar.setLenient(lenient);
return parser.parse(StrUtil.str(str), new ParsePosition(0), calendar) ? calendar : null;
}
}
package cn.hutool.core.date;
import cn.hutool.core.convert.NumberChineseFormatter;
import cn.hutool.core.date.chinese.ChineseMonth;
import cn.hutool.core.date.chinese.GanZhi;
import cn.hutool.core.date.chinese.LunarFestival;
import cn.hutool.core.date.chinese.LunarInfo;
import cn.hutool.core.date.chinese.SolarTerms;
import cn.hutool.core.util.StrUtil;
import java.time.LocalDate;
import java.util.Calendar;
import java.util.Date;
/**
* 农历日期工具,最大支持到2099年,支持:
*
* <ul>
* <li>通过公历日期构造获取对应农历</li>
* <li>通过农历日期直接构造</li>
* </ul>
*
* @author zjw, looly
* @since 5.1.1
*/
public class ChineseDate {
//农历年
private final int year;
//农历月,润N月这个值就是N+1,其他月按照显示月份赋值
private final int month;
// 当前月份是否闰月
private final boolean isLeapMonth;
//农历日
private final int day;
//公历年
private final int gyear;
//公历月,从1开始计数
private final int gmonthBase1;
//公历日
private final int gday;
/**
* 通过公历日期构造
*
* @param date 公历日期
*/
public ChineseDate(Date date) {
this(LocalDateTimeUtil.ofDate(date.toInstant()));
}
/**
* 通过公历日期构造
*
* @param localDate 公历日期
* @since 5.7.22
*/
public ChineseDate(LocalDate localDate) {
// 公历
gyear = localDate.getYear();
gmonthBase1 = localDate.getMonthValue();
gday = localDate.getDayOfMonth();
// 求出和1900年1月31日相差的天数
int offset = (int) (localDate.toEpochDay() - LunarInfo.BASE_DAY);
// 计算农历年份
// 用offset减去每农历年的天数,计算当天是农历第几天,offset是当年的第几天
int daysOfYear;
int iYear;
for (iYear = LunarInfo.BASE_YEAR; iYear <= LunarInfo.MAX_YEAR; iYear++) {
daysOfYear = LunarInfo.yearDays(iYear);
if (offset < daysOfYear) {
break;
}
offset -= daysOfYear;
}
year = iYear;
// 计算农历月份
final int leapMonth = LunarInfo.leapMonth(iYear); // 闰哪个月,1-12
// 用当年的天数offset,逐个减去每月(农历)的天数,求出当天是本月的第几天
int month;
int daysOfMonth;
boolean hasLeapMonth = false;
for (month = 1; month < 13; month++) {
// 闰月,如润的是五月,则5表示五月,6表示润五月
if (leapMonth > 0 && month == (leapMonth + 1)) {
daysOfMonth = LunarInfo.leapDays(year);
hasLeapMonth = true;
} else {
// 普通月,当前面的月份存在闰月时,普通月份要-1,递补闰月的数字
// 如2月是闰月,此时3月实际是第四个月
daysOfMonth = LunarInfo.monthDays(year, hasLeapMonth ? month - 1 : month);
}
if (offset < daysOfMonth) {
// offset不足月,结束
break;
}
offset -= daysOfMonth;
}
this.isLeapMonth = leapMonth > 0 && (month == (leapMonth + 1));
if (hasLeapMonth && false == this.isLeapMonth) {
// 当前月份前有闰月,则月份显示要-1,除非当前月份就是润月
month--;
}
this.month = month;
this.day = offset + 1;
}
/**
* 构造方法传入日期<br>
* 此方法自动判断闰月,如果chineseMonth为本年的闰月,则按照闰月计算
*
* @param chineseYear 农历年
* @param chineseMonth 农历月,1表示一月(正月)
* @param chineseDay 农历日,1表示初一
* @since 5.2.4
*/
public ChineseDate(int chineseYear, int chineseMonth, int chineseDay) {
this(chineseYear, chineseMonth, chineseDay, chineseMonth == LunarInfo.leapMonth(chineseYear));
}
/**
* 构造方法传入日期<br>
* 通过isLeapMonth参数区分是否闰月,如五月是闰月,当isLeapMonth为{@code true}时,表示润五月,{@code false}表示五月
*
* @param chineseYear 农历年
* @param chineseMonth 农历月,1表示一月(正月),如果isLeapMonth为{@code true},1表示润一月
* @param chineseDay 农历日,1表示初一
* @param isLeapMonth 当前月份是否闰月
* @since 5.7.18
*/
public ChineseDate(int chineseYear, int chineseMonth, int chineseDay, boolean isLeapMonth) {
if(chineseMonth != LunarInfo.leapMonth(chineseYear)){
// issue#I5YB1A,用户传入的月份可能非闰月,此时此参数无效。
isLeapMonth = false;
}
this.day = chineseDay;
// 当月是闰月的后边的月定义为闰月,如润的是五月,则5表示五月,6表示润五月
this.isLeapMonth = isLeapMonth;
// 闰月时,农历月份+1,如6表示润五月
this.month = isLeapMonth ? chineseMonth + 1 : chineseMonth;
this.year = chineseYear;
final DateTime dateTime = lunar2solar(chineseYear, chineseMonth, chineseDay, isLeapMonth);
if (null != dateTime) {
//初始化公历年
this.gday = dateTime.dayOfMonth();
//初始化公历月
this.gmonthBase1 = dateTime.month() + 1;
//初始化公历日
this.gyear = dateTime.year();
} else {
//初始化公历年
this.gday = -1;
//初始化公历月
this.gmonthBase1 = -1;
//初始化公历日
this.gyear = -1;
}
}
/**
* 获得农历年份
*
* @return 返回农历年份
*/
public int getChineseYear() {
return this.year;
}
/**
* 获取公历的年
*
* @return 公历年
* @since 5.6.1
*/
public int getGregorianYear() {
return this.gyear;
}
/**
* 获取农历的月,从1开始计数<br>
* 此方法返回实际的月序号,如一月是闰月,则一月返回1,润一月返回2
*
* @return 农历的月
* @since 5.2.4
*/
public int getMonth() {
return this.month;
}
/**
* 获取公历的月,从1开始计数
*
* @return 公历月
* @since 5.6.1
*/
public int getGregorianMonthBase1() {
return this.gmonthBase1;
}
/**
* 获取公历的月,从0开始计数
*
* @return 公历月
* @since 5.6.1
*/
public int getGregorianMonth() {
return this.gmonthBase1 - 1;
}
/**
* 当前农历月份是否为闰月
*
* @return 是否为闰月
* @since 5.4.2
*/
public boolean isLeapMonth() {
return this.isLeapMonth;
}
/**
* 获得农历月份(中文,例如二月,十二月,或者润一月)
*
* @return 返回农历月份
*/
public String getChineseMonth() {
return getChineseMonth(false);
}
/**
* 获得农历月称呼(中文,例如二月,腊月,或者润正月)
*
* @return 返回农历月份称呼
*/
public String getChineseMonthName() {
return getChineseMonth(true);
}
/**
* 获得农历月份(中文,例如二月,十二月,或者润一月)
*
* @param isTraditional 是否传统表示,例如一月传统表示为正月
* @return 返回农历月份
* @since 5.7.18
*/
public String getChineseMonth(boolean isTraditional) {
return ChineseMonth.getChineseMonthName(isLeapMonth(),
isLeapMonth() ? this.month - 1 : this.month, isTraditional);
}
/**
* 获取农历的日,从1开始计数
*
* @return 农历的日,从1开始计数
* @since 5.2.4
*/
public int getDay() {
return this.day;
}
/**
* 获取公历的日
*
* @return 公历日
* @since 5.6.1
*/
public int getGregorianDay() {
return this.gday;
}
/**
* 获得农历日
*
* @return 获得农历日
*/
public String getChineseDay() {
String[] chineseTen = {"初", "十", "廿", "卅"};
int n = (day % 10 == 0) ? 9 : (day % 10 - 1);
if (day > 30) {
return "";
}
switch (day) {
case 10:
return "初十";
case 20:
return "二十";
case 30:
return "三十";
default:
return chineseTen[day / 10] + NumberChineseFormatter.format(n + 1, false);
}
}
/**
* 获取公历的Date
*
* @return 公历Date
* @since 5.6.1
*/
public Date getGregorianDate() {
return DateUtil.date(getGregorianCalendar());
}
/**
* 获取公历的Calendar
*
* @return 公历Calendar
* @since 5.6.1
*/
public Calendar getGregorianCalendar() {
final Calendar calendar = CalendarUtil.calendar();
//noinspection MagicConstant
calendar.set(this.gyear, getGregorianMonth(), this.gday, 0, 0, 0);
return calendar;
}
/**
* 获得节日,闰月不计入节日中
*
* @return 获得农历节日
*/
public String getFestivals() {
return StrUtil.join(",", LunarFestival.getFestivals(this.year, this.month, day));
}
/**
* 获得年份生肖
*
* @return 获得年份生肖
*/
public String getChineseZodiac() {
return Zodiac.getChineseZodiac(this.year);
}
/**
* 获得年的天干地支
*
* @return 获得天干地支
*/
public String getCyclical() {
return GanZhi.getGanzhiOfYear(this.year);
}
/**
* 干支纪年信息
*
* @return 获得天干地支的年月日信息
*/
public String getCyclicalYMD() {
if (gyear >= LunarInfo.BASE_YEAR && gmonthBase1 > 0 && gday > 0) {
return cyclicalm(gyear, gmonthBase1, gday);
}
return null;
}
/**
* 获得节气
*
* @return 获得节气
* @since 5.6.3
*/
public String getTerm() {
return SolarTerms.getTerm(gyear, gmonthBase1, gday);
}
/**
* 转换为标准的日期格式来表示农历日期,例如2020-01-13<br>
* 如果存在闰月,显示闰月月份,如润二月显示2
*
* @return 标准的日期格式
* @since 5.2.4
*/
public String toStringNormal() {
return String.format("%04d-%02d-%02d", this.year,
isLeapMonth() ? this.month - 1 : this.month, this.day);
}
@Override
public String toString() {
return String.format("%s%s年 %s%s", getCyclical(), getChineseZodiac(), getChineseMonthName(), getChineseDay());
}
// ------------------------------------------------------- private method start
/**
* 这里同步处理年月日的天干地支信息
*
* @param year 公历年
* @param month 公历月,从1开始
* @param day 公历日
* @return 天干地支信息
*/
private String cyclicalm(int year, int month, int day) {
return StrUtil.format("{}年{}月{}日",
GanZhi.getGanzhiOfYear(this.year),
GanZhi.getGanzhiOfMonth(year, month, day),
GanZhi.getGanzhiOfDay(year, month, day));
}
/**
* 通过农历年月日信息 返回公历信息 提供给构造函数
*
* @param chineseYear 农历年
* @param chineseMonth 农历月
* @param chineseDay 农历日
* @param isLeapMonth 传入的月是不是闰月
* @return 公历信息
*/
private DateTime lunar2solar(int chineseYear, int chineseMonth, int chineseDay, boolean isLeapMonth) {
//超出了最大极限值
if ((chineseYear == 2100 && chineseMonth == 12 && chineseDay > 1) ||
(chineseYear == LunarInfo.BASE_YEAR && chineseMonth == 1 && chineseDay < 31)) {
return null;
}
int day = LunarInfo.monthDays(chineseYear, chineseMonth);
int _day = day;
if (isLeapMonth) {
_day = LunarInfo.leapDays(chineseYear);
}
//参数合法性效验
if (chineseYear < LunarInfo.BASE_YEAR || chineseYear > 2100 || chineseDay > _day) {
return null;
}
//计算农历的时间差
int offset = 0;
for (int i = LunarInfo.BASE_YEAR; i < chineseYear; i++) {
offset += LunarInfo.yearDays(i);
}
int leap;
boolean isAdd = false;
for (int i = 1; i < chineseMonth; i++) {
leap = LunarInfo.leapMonth(chineseYear);
if (false == isAdd) {//处理闰月
if (leap <= i && leap > 0) {
offset += LunarInfo.leapDays(chineseYear);
isAdd = true;
}
}
offset += LunarInfo.monthDays(chineseYear, i);
}
//转换闰月农历 需补充该年闰月的前一个月的时差
if (isLeapMonth) {
offset += day;
}
//1900年农历正月一日的公历时间为1900年1月30日0时0分0秒(该时间也是本农历的最开始起始点) -2203804800000
return DateUtil.date(((offset + chineseDay - 31) * 86400000L) - 2203804800000L);
}
// ------------------------------------------------------- private method end
}
package cn.hutool.core.date;
import cn.hutool.core.lang.Assert;
import java.io.Serializable;
import java.util.Calendar;
import java.util.Date;
/**
* 日期间隔
*
* @author Looly
*/
public class DateBetween implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 开始日期
*/
private final Date begin;
/**
* 结束日期
*/
private final Date end;
/**
* 创建<br>
* 在前的日期做为起始时间,在后的做为结束时间,间隔只保留绝对值正数
*
* @param begin 起始时间
* @param end 结束时间
* @return DateBetween
* @since 3.2.3
*/
public static DateBetween create(Date begin, Date end) {
return new DateBetween(begin, end);
}
/**
* 创建<br>
* 在前的日期做为起始时间,在后的做为结束时间,间隔只保留绝对值正数
*
* @param begin 起始时间
* @param end 结束时间
* @param isAbs 日期间隔是否只保留绝对值正数
* @return DateBetween
* @since 3.2.3
*/
public static DateBetween create(Date begin, Date end, boolean isAbs) {
return new DateBetween(begin, end, isAbs);
}
/**
* 构造<br>
* 在前的日期做为起始时间,在后的做为结束时间,间隔只保留绝对值正数
*
* @param begin 起始时间
* @param end 结束时间
*/
public DateBetween(Date begin, Date end) {
this(begin, end, true);
}
/**
* 构造<br>
* 在前的日期做为起始时间,在后的做为结束时间
*
* @param begin 起始时间
* @param end 结束时间
* @param isAbs 日期间隔是否只保留绝对值正数
* @since 3.1.1
*/
public DateBetween(Date begin, Date end, boolean isAbs) {
Assert.notNull(begin, "Begin date is null !");
Assert.notNull(end, "End date is null !");
if (isAbs && begin.after(end)) {
// 间隔只为正数的情况下,如果开始日期晚于结束日期,置换之
this.begin = end;
this.end = begin;
} else {
this.begin = begin;
this.end = end;
}
}
/**
* 判断两个日期相差的时长<br>
* 返回 给定单位的时长差
*
* @param unit 相差的单位:相差 天{@link DateUnit#DAY}、小时{@link DateUnit#HOUR} 等
* @return 时长差
*/
public long between(DateUnit unit) {
long diff = end.getTime() - begin.getTime();
return diff / unit.getMillis();
}
/**
* 计算两个日期相差月数<br>
* 在非重置情况下,如果起始日期的天大于结束日期的天,月数要少算1(不足1个月)
*
* @param isReset 是否重置时间为起始时间(重置天时分秒)
* @return 相差月数
* @since 3.0.8
*/
public long betweenMonth(boolean isReset) {
final Calendar beginCal = DateUtil.calendar(begin);
final Calendar endCal = DateUtil.calendar(end);
final int betweenYear = endCal.get(Calendar.YEAR) - beginCal.get(Calendar.YEAR);
final int betweenMonthOfYear = endCal.get(Calendar.MONTH) - beginCal.get(Calendar.MONTH);
int result = betweenYear * 12 + betweenMonthOfYear;
if (false == isReset) {
endCal.set(Calendar.YEAR, beginCal.get(Calendar.YEAR));
endCal.set(Calendar.MONTH, beginCal.get(Calendar.MONTH));
long between = endCal.getTimeInMillis() - beginCal.getTimeInMillis();
if (between < 0) {
return result - 1;
}
}
return result;
}
/**
* 计算两个日期相差年数<br>
* 在非重置情况下,如果起始日期的月大于结束日期的月,年数要少算1(不足1年)
*
* @param isReset 是否重置时间为起始时间(重置月天时分秒)
* @return 相差年数
* @since 3.0.8
*/
public long betweenYear(boolean isReset) {
final Calendar beginCal = DateUtil.calendar(begin);
final Calendar endCal = DateUtil.calendar(end);
int result = endCal.get(Calendar.YEAR) - beginCal.get(Calendar.YEAR);
if (false == isReset) {
// 考虑闰年的2月情况
if (Calendar.FEBRUARY == beginCal.get(Calendar.MONTH) && Calendar.FEBRUARY == endCal.get(Calendar.MONTH)) {
if (beginCal.get(Calendar.DAY_OF_MONTH) == beginCal.getActualMaximum(Calendar.DAY_OF_MONTH)
&& endCal.get(Calendar.DAY_OF_MONTH) == endCal.getActualMaximum(Calendar.DAY_OF_MONTH)) {
// 两个日期都位于2月的最后一天,此时月数按照相等对待,此时都设置为1号
beginCal.set(Calendar.DAY_OF_MONTH, 1);
endCal.set(Calendar.DAY_OF_MONTH, 1);
}
}
endCal.set(Calendar.YEAR, beginCal.get(Calendar.YEAR));
long between = endCal.getTimeInMillis() - beginCal.getTimeInMillis();
if (between < 0) {
return result - 1;
}
}
return result;
}
/**
* 格式化输出时间差
*
* @param unit 日期单位
* @param level 级别
* @return 字符串
* @since 5.7.17
*/
public String toString(DateUnit unit, BetweenFormatter.Level level) {
return DateUtil.formatBetween(between(unit), level);
}
/**
* 格式化输出时间差
*
* @param level 级别
* @return 字符串
*/
public String toString(BetweenFormatter.Level level) {
return toString(DateUnit.MS, level);
}
@Override
public String toString() {
return toString(BetweenFormatter.Level.MILLISECOND);
}
}
package cn.hutool.core.date;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.util.StrUtil;
/**
* 工具类异常
* @author xiaoleilu
*/
public class DateException extends RuntimeException{
private static final long serialVersionUID = 8247610319171014183L;
public DateException(Throwable e) {
super(ExceptionUtil.getMessage(e), e);
}
public DateException(String message) {
super(message);
}
public DateException(String messageTemplate, Object... params) {
super(StrUtil.format(messageTemplate, params));
}
public DateException(String message, Throwable throwable) {
super(message, throwable);
}
public DateException(Throwable throwable, String messageTemplate, Object... params) {
super(StrUtil.format(messageTemplate, params), throwable);
}
}
package cn.hutool.core.date;
import java.util.Calendar;
/**
* 日期各个部分的枚举<br>
* 与Calendar相应值对应
*
* @author Looly
*
*/
public enum DateField {
/**
* 世纪
*
* @see Calendar#ERA
*/
ERA(Calendar.ERA),
/**
* 年
*
* @see Calendar#YEAR
*/
YEAR(Calendar.YEAR),
/**
* 月
*
* @see Calendar#MONTH
*/
MONTH(Calendar.MONTH),
/**
* 一年中第几周
*
* @see Calendar#WEEK_OF_YEAR
*/
WEEK_OF_YEAR(Calendar.WEEK_OF_YEAR),
/**
* 一月中第几周
*
* @see Calendar#WEEK_OF_MONTH
*/
WEEK_OF_MONTH(Calendar.WEEK_OF_MONTH),
/**
* 一月中的第几天
*
* @see Calendar#DAY_OF_MONTH
*/
DAY_OF_MONTH(Calendar.DAY_OF_MONTH),
/**
* 一年中的第几天
*
* @see Calendar#DAY_OF_YEAR
*/
DAY_OF_YEAR(Calendar.DAY_OF_YEAR),
/**
* 周几,1表示周日,2表示周一
*
* @see Calendar#DAY_OF_WEEK
*/
DAY_OF_WEEK(Calendar.DAY_OF_WEEK),
/**
* 天所在的周是这个月的第几周
*
* @see Calendar#DAY_OF_WEEK_IN_MONTH
*/
DAY_OF_WEEK_IN_MONTH(Calendar.DAY_OF_WEEK_IN_MONTH),
/**
* 上午或者下午
*
* @see Calendar#AM_PM
*/
AM_PM(Calendar.AM_PM),
/**
* 小时,用于12小时制
*
* @see Calendar#HOUR
*/
HOUR(Calendar.HOUR),
/**
* 小时,用于24小时制
*
* @see Calendar#HOUR
*/
HOUR_OF_DAY(Calendar.HOUR_OF_DAY),
/**
* 分钟
*
* @see Calendar#MINUTE
*/
MINUTE(Calendar.MINUTE),
/**
* 秒
*
* @see Calendar#SECOND
*/
SECOND(Calendar.SECOND),
/**
* 毫秒
*
* @see Calendar#MILLISECOND
*/
MILLISECOND(Calendar.MILLISECOND);
// ---------------------------------------------------------------
private final int value;
DateField(int value) {
this.value = value;
}
public int getValue() {
return this.value;
}
/**
* 将 {@link Calendar}相关值转换为DatePart枚举对象<br>
*
* @param calendarPartIntValue Calendar中关于Week的int值
* @return DateField
*/
public static DateField of(int calendarPartIntValue) {
switch (calendarPartIntValue) {
case Calendar.ERA:
return ERA;
case Calendar.YEAR:
return YEAR;
case Calendar.MONTH:
return MONTH;
case Calendar.WEEK_OF_YEAR:
return WEEK_OF_YEAR;
case Calendar.WEEK_OF_MONTH:
return WEEK_OF_MONTH;
case Calendar.DAY_OF_MONTH:
return DAY_OF_MONTH;
case Calendar.DAY_OF_YEAR:
return DAY_OF_YEAR;
case Calendar.DAY_OF_WEEK:
return DAY_OF_WEEK;
case Calendar.DAY_OF_WEEK_IN_MONTH:
return DAY_OF_WEEK_IN_MONTH;
case Calendar.AM_PM:
return AM_PM;
case Calendar.HOUR:
return HOUR;
case Calendar.HOUR_OF_DAY:
return HOUR_OF_DAY;
case Calendar.MINUTE:
return MINUTE;
case Calendar.SECOND:
return SECOND;
case Calendar.MILLISECOND:
return MILLISECOND;
default:
return null;
}
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment