!12 完成时间工具与随机字符串工具的改造
Merge pull request !12 from 彭宇琦/featrue/20210115-工具简单改造
This commit is contained in:
commit
b00868ebd7
|
@ -194,10 +194,7 @@ public class Functions {
|
|||
* @return 返回处理后的时间
|
||||
*/
|
||||
private static String disposeTime(String timeText, String pattern) {
|
||||
Time time = new Time(timeText);
|
||||
time.addTime(pattern);
|
||||
|
||||
return time.getFormatTime();
|
||||
return Time.parse(timeText).addTime(pattern).getFormatTime();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -70,7 +70,7 @@ public class TestNGDataDriver {
|
|||
/**
|
||||
* 用于对日期格式或特殊字段输入的日期进行转换
|
||||
*/
|
||||
private Time time = new Time();
|
||||
private Time time = Time.parse();
|
||||
|
||||
/**
|
||||
* 构造对象,初始化数据
|
||||
|
@ -332,7 +332,7 @@ public class TestNGDataDriver {
|
|||
* @return {@link Time}类型的数据
|
||||
*/
|
||||
public Time getTime(int index) {
|
||||
return new Time(getString(index));
|
||||
return Time.parse(getString(index));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -342,7 +342,7 @@ public class TestNGDataDriver {
|
|||
* @return {@link Time}类型的数据
|
||||
*/
|
||||
public Time getTime(String listName) {
|
||||
return new Time(getString(listName));
|
||||
return Time.parse(getString(listName));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -272,7 +272,7 @@ public class ExcelRecord extends AbstractWriteExcel<ExcelRecord> {
|
|||
switchSheet("运行记录")
|
||||
.addContent("state", isError ? "2" : "1")
|
||||
.addContent("bug_number", String.valueOf(resultBugList.size()))
|
||||
.addContent("active_time", new Time().getFormatTime())
|
||||
.addContent("active_time", Time.parse().getFormatTime())
|
||||
.addContent("use_time", startTime == 0L ? "" : (String.valueOf((System.currentTimeMillis() - startTime) / 1000.0) + "s"));
|
||||
|
||||
//获取父类的end方法,结束当前的记录
|
||||
|
|
|
@ -1,46 +1,49 @@
|
|||
package com.auxiliary.tool.data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
import java.util.Random;
|
||||
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
/**
|
||||
* <p><b>文件名:</b>RandomString.java</p>
|
||||
* <p><b>用途:</b>
|
||||
* 提供根据字符串池(产生随机字符串的范围)中添加模型,返回相应的随机字符串的方法
|
||||
* <p>
|
||||
* <b>文件名:</b>RandomString.java
|
||||
* </p>
|
||||
* <p><b>编码时间:</b>2019年2月13日下午19:53:01</p>
|
||||
* <p><b>修改时间:</b>2021年1月13日下午12:53:01</p>
|
||||
* <p>
|
||||
* <b>用途:</b> 提供根据字符串池(产生随机字符串的范围)中添加模型,返回相应的随机字符串的方法。
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>编码时间:</b>2019年2月13日下午19:53:01
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>修改时间:</b>2021年1月16日下午12:53:01
|
||||
* </p>
|
||||
*
|
||||
* @author 彭宇琦
|
||||
* @version Ver1.9
|
||||
* @version Ver1.10
|
||||
* @since JDK 1.8
|
||||
*
|
||||
*/
|
||||
public class RandomString {
|
||||
// 用于定义随机字符串产生的范围
|
||||
/**
|
||||
* 字符串池
|
||||
*/
|
||||
private StringBuilder stringSeed = new StringBuilder("");
|
||||
// 用于控制产生的随机字符串是否允许有重复字符的开关
|
||||
/**
|
||||
* 控制产生的随机字符串是否允许有重复字符的开关
|
||||
*/
|
||||
private boolean repeat = true;
|
||||
|
||||
/**
|
||||
* 忽略,只生成一个与随机字符串范围长度相同的随机字符串
|
||||
* 指定通过{@link #toString()}方法默认输出的字符串长度
|
||||
*/
|
||||
public final int DISPOSE_IGNORE = 0;
|
||||
/**
|
||||
* 抛出异常,中断生成字符串的操作
|
||||
*/
|
||||
public final int DISPOSE_THROW_EXCEPTION = 1;
|
||||
/**
|
||||
* 重复,将随机字符串的生成条件改为允许字符串重复
|
||||
*/
|
||||
public final int DISPOSE_REPEAT = 2;
|
||||
|
||||
// 用于控制生成允许重复字符的随机字符串时,其错误的处理方式,默认为重复
|
||||
private int dispose = DISPOSE_REPEAT;
|
||||
public static int defaultLength = 6;
|
||||
|
||||
/**
|
||||
* 指向StringMode枚举类,可通过该属性向字符串池中添加模型
|
||||
* 控制在需要生成的字符串大于字符串池时的处理方式
|
||||
*/
|
||||
public StringMode mode;
|
||||
private RepeatDisposeType dispose = RepeatDisposeType.DISPOSE_REPEAT;
|
||||
|
||||
/**
|
||||
* 初始化字符串池,使其不包含任何元素
|
||||
|
@ -51,511 +54,481 @@ public class RandomString {
|
|||
/**
|
||||
* 通过预设模型模型对字符串池进行初始化
|
||||
*
|
||||
* @param modes
|
||||
* 需要加入字符串池中的模型(为StringMode枚举对象)
|
||||
* @param stringModes 需要加入字符串池中的模型(为{@link StringMode}枚举对象)
|
||||
*/
|
||||
public RandomString(StringMode... modes) {
|
||||
addMode(modes);
|
||||
public RandomString(StringMode... stringModes) {
|
||||
addMode(stringModes);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过自定义的字符串对字符串池进行初始化
|
||||
*
|
||||
* @param mode
|
||||
* 需要加入字符串池中的模型(为StringMode枚举对象)
|
||||
* @param mode 需要加入字符串池中的模型
|
||||
*/
|
||||
public RandomString(String mode) {
|
||||
addMode(mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回是否允许产生的随机字符串字符重复结果
|
||||
* 设置产生的随机字符串中是否允许存在重复的字符,默认为允许重复。
|
||||
* <p>
|
||||
* <b>注意:</b>随机字符串字符的重复是相对于字符串池而言的,若字符串池中本身存在重复的字符,则
|
||||
* 即便设置了不允许出现字符,在生成的随机字符串中也可能包含重复的字符。若要生成不包含重复字符的
|
||||
* 字符串,可调用{@link #removeRepetition()}方法,去除字符串池中重复的字符后,再调用返回字符串 的方法。
|
||||
* </p>
|
||||
*
|
||||
* @return 是否允许随机字符串字符串字符重复
|
||||
*/
|
||||
public boolean isRepeat() {
|
||||
return repeat;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置产生的随机字符串中的字符是否允许重复,默认允许重复,当设置不允许重复时,若需要生成随机字符串的
|
||||
* 长度大于随机字符串生成范围的长度时,需要配合{@link #setDispose(int)}方法联合使用,有三种状态:<br/>
|
||||
* {@link #DISPOSE_IGNORE}:忽略,只生成一个与随机字符串范围长度相同的随机字符串<br/>
|
||||
* {@link #DISPOSE_THROW_EXCEPTION}:抛出异常,中断生成字符串的操作<br/>
|
||||
* {@link #DISPOSE_REPEAT}:重复,生成的随机字符串可带重复的字符<br/>
|
||||
*
|
||||
* @param repeat
|
||||
* 是否允许重复
|
||||
* @param repeat 是否允许重复
|
||||
*/
|
||||
public void setRepeat(boolean repeat) {
|
||||
this.repeat = repeat;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于返回产生的随机字符串大于字符串生成范围时的处理方式,其值对应如下:<br/>
|
||||
* 0 = {@link #DISPOSE_IGNORE}<br/>
|
||||
* 1 = {@link #DISPOSE_THROW_EXCEPTION}<br/>
|
||||
* 2 = {@link #DISPOSE_REPEAT}<br/>
|
||||
* 用于设置需要产生的随机字符串长度大于字符串池长度,且设置了不允许出现重复字符时的处理方式。
|
||||
* <p>
|
||||
* 若需要产生的随机字符串长度大于字符串池长度,则必定会出现重复的字符。若同时调用
|
||||
* {@link #setRepeat(boolean)}方法设置不允许存在重复字符时,则需要对字符串的生成进行一定的处理。
|
||||
* 具体的处理规则,可参照{@link RepeatDisposeType}枚举中的说明
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>注意:</b>
|
||||
* <ol>
|
||||
* <li>若未设置,则按照默认的{@link #DISPOSE_REPEAT}方式进行处理</li>
|
||||
* <li>处理方式为{@link #DISPOSE_REPEAT}时,在处理后,不影响{@link #setRepeat(boolean)}的设置</li>
|
||||
* </ol>
|
||||
* </p>
|
||||
*
|
||||
* @return 处理方式
|
||||
* @param dispose 处理方式{@link RepeatDisposeType}枚举
|
||||
*/
|
||||
public int getDispose() {
|
||||
return dispose;
|
||||
public void setDispose(RepeatDisposeType repeatDisposeType) {
|
||||
this.dispose = repeatDisposeType;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于设置产生的随机字符串大于字符串生成范围时的处理方式,有三种操作方式:<br/>
|
||||
* {@link #DISPOSE_IGNORE}:忽略,只生成一个与随机字符串范围长度相同的随机字符串<br/>
|
||||
* {@link #DISPOSE_THROW_EXCEPTION}:抛出异常,中断生成字符串的操作<br/>
|
||||
* {@link #DISPOSE_REPEAT}:重复,将随机字符串的生成条件改为允许字符串重复<br/>
|
||||
* 注意:<br/>
|
||||
* 1.若设置不正确则按照重{@link #DISPOSE_REPEAT}方式进行处理<br/>
|
||||
* 2.处理方式为{@link #DISPOSE_REPEAT}时,会改临时改变变允许重复的控制开关,不会永久生效<br/>
|
||||
* 3.处理方式为{@link #DISPOSE_REPEAT}时,会生成一串与随机字符串范围长度相同字符串,之后重复的字符在其后增加
|
||||
* 用于返回字符串池
|
||||
*
|
||||
* @param dispose
|
||||
* 处理方式,见类中的三种处理方式:{@link #DISPOSE_IGNORE}、{@link #DISPOSE_THROW_EXCEPTION}、{@link #DISPOSE_REPEAT}
|
||||
*/
|
||||
public void setDispose(int dispose) {
|
||||
this.dispose = dispose;
|
||||
}
|
||||
|
||||
/**
|
||||
* 该方法用于返回字符串池
|
||||
*
|
||||
* @return 用于返回随机字符串生成的范围
|
||||
* @return 字符串池
|
||||
*/
|
||||
public String getStringSeed() {
|
||||
return stringSeed.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 该方法用于向字符串池中添加模型,通过该方法添加的模型将不检查字符串池中是否存在与之重复的元素
|
||||
* 用于向字符串池中添加模型,通过该方法添加的模型将不检查字符串池中是否存在与之重复的元素
|
||||
*
|
||||
* @param modes
|
||||
* 需要加入到字符串池中的模型
|
||||
* @param stringModes 字符串模型枚举{@link StringMode}
|
||||
* @return 类本身
|
||||
*/
|
||||
/**
|
||||
* 该方法用于向字符串池中添加模型,通过该方法添加的模型将不检查字符串池中是否存在与之重复的元素
|
||||
*
|
||||
* @param modes
|
||||
* 需要加入到字符串池中的模型
|
||||
* @return 返回类本身,以便于链式操作
|
||||
*/
|
||||
public RandomString addMode(StringMode... modes) {
|
||||
for (StringMode m : modes) {
|
||||
stringSeed.append(m.getSeed());
|
||||
}
|
||||
|
||||
return this;
|
||||
public RandomString addMode(StringMode... stringModes) {
|
||||
return addMode(true, stringModes);
|
||||
}
|
||||
|
||||
/**
|
||||
* 该方法用于向字符串池中添加模型,且通过isRepeat进行判断是否允许添加可重复的字符串进入字符串池
|
||||
* 用于向字符串池中添加模型,且通过isRepeat进行判断是否允许添加可重复的字符串进入字符串池
|
||||
*
|
||||
* @param isRepeat
|
||||
* 字符串池中的元素是否可重复
|
||||
* @param modes
|
||||
* 需要加入到字符串池中的模型
|
||||
*
|
||||
* @return 返回类本身,以便于链式操作
|
||||
* @param isRepeat 字符串池中的元素是否可重复
|
||||
* @param stringModes 字符串模型枚举{@link StringMode}
|
||||
*
|
||||
* @return 类本身
|
||||
*/
|
||||
public RandomString addMode(boolean isRepeat, StringMode... modes) {
|
||||
// 判断传入的参数是否允许字符串池中元素重复,若为true,则等同于调用addMode(StringMode... modes)
|
||||
if (!isRepeat) {
|
||||
// 循环,读取所有传入的模型
|
||||
for (StringMode m : modes) {
|
||||
// 判断模型整体是否已经存在,若存在则不进行添加
|
||||
if (stringSeed.indexOf(m.getSeed()) > -1) {
|
||||
continue;
|
||||
}
|
||||
public RandomString addMode(boolean isRepeat, StringMode... stringModes) {
|
||||
StringBuilder joinText = new StringBuilder("");
|
||||
Optional.ofNullable(stringModes)
|
||||
// 过滤掉无元素的数组
|
||||
.filter(arr -> arr.length != 0)
|
||||
// 将数组转换为集合,若数组有误,则返回空集合
|
||||
.map(Arrays::asList).orElse(new ArrayList<>())
|
||||
// 读取集合每一个元素,并返回相应的字符串
|
||||
.stream().map(StringMode::getSeed).forEach(joinText::append);
|
||||
|
||||
packageString(m.getSeed());
|
||||
}
|
||||
} else {
|
||||
addMode(modes);
|
||||
}
|
||||
|
||||
return this;
|
||||
return addMode(isRepeat, joinText.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* 该方法用于向字符串池中添加自定义的字符串,通过该方法添加的字符串将不检查字符串池中是否存在与之重复的元素
|
||||
* 用于向字符串池中添加自定义的字符串,通过该方法添加的字符串将不检查字符串池中是否存在与之重复的元素
|
||||
*
|
||||
* @param mode
|
||||
* 需要加入到字符串池中的模型
|
||||
*
|
||||
* @return 返回类本身,以便于链式操作
|
||||
* @param mode 需要加入到字符串池中的模型
|
||||
*
|
||||
* @return 类本身
|
||||
*/
|
||||
public RandomString addMode(String mode) {
|
||||
stringSeed.append(mode);
|
||||
|
||||
return this;
|
||||
return addMode(true, mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 该方法用于向字符串池中添加自定义的字符串,且通过isRepeat进行判断是否允许添加可重复的字符串进入字符串池
|
||||
* 用于向字符串池中添加自定义的字符串,且通过isRepeat进行判断是否允许添加可重复的字符串进入字符串池
|
||||
*
|
||||
* @param isRepeat
|
||||
* 字符串池中的元素是否可重复
|
||||
* @param mode
|
||||
* 需要加入到字符串池中的模型
|
||||
* @param isRepeat 字符串池中的元素是否可重复
|
||||
* @param mode 需要加入到字符串池中的模型
|
||||
*
|
||||
* @return 返回类本身,以便于链式操作
|
||||
* @return 类本身
|
||||
*/
|
||||
public RandomString addMode(boolean isRepeat, String mode) {
|
||||
// 判断传入的参数是否允许字符串池中元素重复,若为true,则等同于调用addMode(StringMode... modes)
|
||||
if (!isRepeat) {
|
||||
// 判断模型整体是否已经存在,若存在则不进行添加
|
||||
if (stringSeed.indexOf(mode) > -1) {
|
||||
return this;
|
||||
}
|
||||
|
||||
packageString(mode);
|
||||
} else {
|
||||
addMode(mode);
|
||||
}
|
||||
|
||||
joinStringSeed(isRepeat, mode);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 该方法用于清空StringSeed中存储的随机字符串生成范围
|
||||
* 用于清空字符串池的内容
|
||||
*/
|
||||
public void clear() {
|
||||
stringSeed.replace(0, (stringSeed.length()), ""); // 将随机字符串生成范围清空
|
||||
if (stringSeed.length() != 0) {
|
||||
stringSeed.delete(0, stringSeed.length());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 该方法用于返回StringSeed的长度(随机字符串生成范围的长度)
|
||||
* 用于返回字符串池的长度
|
||||
*
|
||||
* @return 返回随机字符串生成范围StringSeed的长度
|
||||
* @return 字符串池的长度
|
||||
*/
|
||||
public int length() {
|
||||
return stringSeed.length();
|
||||
}
|
||||
|
||||
/**
|
||||
* 该类用于在随机字符串生成范围中删除由用户指定的所有符合条件的字符串
|
||||
* 用于删除字符串池中指定的字符串
|
||||
*
|
||||
* @param str
|
||||
* 用户指定需要从随机字符串生成范围中删除的字符串
|
||||
* @return 返回的字符串,若输入的字符串错误,则返回null
|
||||
* @see #remove(int)
|
||||
* @see #remove(int, int)
|
||||
* @param str 需要删除的字符串
|
||||
*/
|
||||
public String remove(String str) {
|
||||
public void remove(String str) {
|
||||
// 判断StringSeed是否为空,为空则返回false
|
||||
if (stringSeed.length() == 0) {
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
// 判断用户指定需要移除的字符串是否为空,如果为空,则返回false
|
||||
if (str.equals("")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 用于存储在StringSeed中查找到包含用户指定指定字符串str的位置
|
||||
int StartPos = stringSeed.indexOf(str);
|
||||
|
||||
// 判断整个StringSeed中是否包含指定的字符串,没有找到,则返回false
|
||||
if (StartPos < 0) // 如果无法找到与Char相匹配的字符串
|
||||
{
|
||||
return null; // 删除失败,返回false
|
||||
}
|
||||
|
||||
// 循环,在StringSeed中移除指定的字符串
|
||||
while (StartPos > 0) {
|
||||
stringSeed.delete(StartPos, StartPos + str.length());// 在StringSeed中移除指定的字符串
|
||||
StartPos = stringSeed.indexOf(str, StartPos);// 重新查找StringSeed是否还包含str
|
||||
}
|
||||
|
||||
return str;// 删除结束,返回true
|
||||
// 对待删除的字符串进行过滤
|
||||
Optional.ofNullable(str).filter(text -> !text.isEmpty())
|
||||
.filter(text -> stringSeed.indexOf(text) > -1)
|
||||
.ifPresent(text -> {
|
||||
int index = -1;
|
||||
// 循环,直到字符串被完全删除为止
|
||||
while ((index = stringSeed.indexOf(text)) > -1) {
|
||||
remove(index, index + text.length());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于在随机字符串生成范围中删除由用户指定范围内(字符串的位置是从0开始)的字符串
|
||||
* 用于删除字符串池中指定范围的字符串。若两个下标相等,则表示删除指定下标的字符串
|
||||
* <p>
|
||||
* <b>注意:</b>指定的范围中,删除的元素包括起始位置的元素,但不包括结束位置的元素,例如:
|
||||
* <code><pre>
|
||||
* StringSeed.append("0123456789");
|
||||
* remove(0, 3);
|
||||
* System.out.println(StringSeed.toString());
|
||||
* </pre></code>
|
||||
* 输出结果为:3456789
|
||||
* <b>注意:</b>
|
||||
* <ol>
|
||||
* <li>指定的范围中,删除的元素包括起始位置的元素,但不包括结束位置的元素</li>
|
||||
* <li>在指定的范围不正确时,将有如下的处理方式:
|
||||
* <ul>
|
||||
* <li>若起始下标大于结束下标时,则调换下标位置</li>
|
||||
* <li>若起始下标小于0时:
|
||||
* <ul>
|
||||
* <li>结束下标大于0,则设置起始下标为0</li>
|
||||
* <li>结束下标小于等于0,则返回空串,并不做任何删除</li>
|
||||
* </ul>
|
||||
* </li>
|
||||
* <li>结束下标大于字符串池长度时:
|
||||
* <ul>
|
||||
* <li>起始下标小于字符串池长度,则设置结束下标为字符串池长度</li>
|
||||
* <li>起始下标大于等于字符串池长度,则返回空串,并不做任何删除</li>
|
||||
* </ul>
|
||||
* </li>
|
||||
* </ul>
|
||||
* </li>
|
||||
* </ol>
|
||||
* </p>
|
||||
* <p>
|
||||
*
|
||||
* @param startPos
|
||||
* 表示用户指定范围的起始位置(包括该位置的元素)
|
||||
* @param endPos
|
||||
* 表示用户指定范围的结束位置(不包括该位置的元素)
|
||||
* @param startIndex 表示用户指定范围的起始位置(包括该位置的元素)
|
||||
* @param endIndex 表示用户指定范围的结束位置(不包括该位置的元素)
|
||||
* @return 返回的字符串,若输入的位置不正确,则返回null
|
||||
* @see #remove(int)
|
||||
* @see #remove(String)
|
||||
*/
|
||||
public String remove(int startPos, int endPos) {
|
||||
public String remove(int startIndex, int endIndex) {
|
||||
// 判断StringSeed是否为空,为空则返回false
|
||||
if (stringSeed.length() == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 判断用户指定开始位置是否大于结束位置,大于则返回false
|
||||
if (startPos > endPos) {
|
||||
int temp = startPos;
|
||||
startPos = endPos;
|
||||
endPos = temp;
|
||||
}
|
||||
|
||||
// 判断用户指定位置是否符合StringSeed的范围,不符合则返回false
|
||||
if (startPos < 0 || endPos > stringSeed.length()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String s = stringSeed.substring(startPos, endPos);
|
||||
stringSeed.delete(startPos, endPos);// 删除指定位置的字符串
|
||||
|
||||
// 返回被删除的字符串
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* 该类用于在随机字符串生成范围中删除由用户指定位置(字符串的位置是从0开始)的字符串<br/>
|
||||
* 例如:
|
||||
* <pre><code>
|
||||
* StringSeed.append("0123456789");
|
||||
* remove(2);
|
||||
* System.out.println(StringSeed.toString());
|
||||
* </code></pre>
|
||||
* 输出结果为:<br/>
|
||||
* 013456789
|
||||
*
|
||||
* @param pos 表示用户指定位置
|
||||
* @return 返回的字符串,若输入的位置不正确,则返回null
|
||||
* @see #remove(String)
|
||||
* @see #remove(int, int)
|
||||
*/
|
||||
public String remove(int pos) {
|
||||
return remove(pos, pos + 1);// 删除成功,返回true
|
||||
}
|
||||
|
||||
/**
|
||||
* 该方法用于移除随机字符串生成范围中重复的字符,以达到范围中字符串不会重复的情况
|
||||
*
|
||||
* @return 返回移除字符串的状态,true表示移除成功,false表示移除失败
|
||||
*/
|
||||
public boolean removeRepetition() {
|
||||
// 判断StringSeed是否为空,为空则返回false
|
||||
if (stringSeed.length() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 用于保存删除重复元素后的字符串
|
||||
StringBuilder s = new StringBuilder();
|
||||
|
||||
// 循环,拆分并删除字符串重复元素
|
||||
for (int i = 0; i < stringSeed.length(); i++) {
|
||||
// 判断元素是否在s中存在,存在则不添加
|
||||
if (s.indexOf(getStringSeed().substring(i, i + 1)) > -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 不存在的字符串,则添加进s中
|
||||
s.append(getStringSeed().substring(i, i + 1));
|
||||
}
|
||||
|
||||
// 判断新字符串与原字符串是否相同,相同则说明未进行改动,返回false
|
||||
if (s.toString().equals(getStringSeed())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
clear();// 调用clear(),清空StringSeed
|
||||
stringSeed.append(s.toString());// 将s中的元素放入StringSeed中
|
||||
return true;//
|
||||
}
|
||||
|
||||
/**
|
||||
* 乱序随机字符串产生的范围
|
||||
*/
|
||||
public void shuffle() {
|
||||
// 定义临时存储乱序后的字符串
|
||||
StringBuilder s = new StringBuilder();
|
||||
|
||||
// 循环,使字符串产生范围乱序
|
||||
while (true) {
|
||||
// 判断字符串产生范围剩余量,若其余量为0,则表示随机字符串范围已被清空,则结束循环
|
||||
if (stringSeed.length() == 0) {
|
||||
break;
|
||||
}
|
||||
// 以删除的方式来逐渐清空stringSeed,并将删除的字符拼接到s
|
||||
s.append(remove(new Random().nextInt(stringSeed.length())));
|
||||
}
|
||||
|
||||
// 将生成的乱序范围重新赋予至stringSeed中
|
||||
stringSeed = s;
|
||||
}
|
||||
|
||||
/**
|
||||
* 以默认方式返回生成的随机字符串,默认长度为6个字符
|
||||
*
|
||||
* @return 生成的6个字符长度的字符串
|
||||
* @see #toString(int)
|
||||
* @see #toString(int, int)
|
||||
* @throws IllegalDataException 产生字符串不允许重复,且字符串产生范围长度小于6位,处理方式为抛出异常时抛出
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
// 判断随机字符串生成范围是否为空,为空则直接返回空字符串
|
||||
if (stringSeed.length() == 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return joinString(6);
|
||||
// 判断最大生成长度与最小生成长度的关系
|
||||
if (startIndex > endIndex) {
|
||||
int temp = startIndex;
|
||||
startIndex = endIndex;
|
||||
endIndex = temp;
|
||||
}
|
||||
|
||||
// 判断最小下标是否小于0
|
||||
if (startIndex < 0) {
|
||||
// 再判断最大下标是否大于0,大于0则将最小下标为1;
|
||||
if (endIndex >= 0) {
|
||||
startIndex = 0;
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
// 判断最大下标是否大于字符串池长度
|
||||
if (endIndex >= stringSeed.length()) {
|
||||
// 再判断最小下标是否小于字符串池长度
|
||||
if (startIndex < stringSeed.length()) {
|
||||
endIndex = stringSeed.length();
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
//判断两个下标是否一致
|
||||
if (startIndex == endIndex) {
|
||||
endIndex += 1;
|
||||
}
|
||||
|
||||
String delectStr = stringSeed.substring(startIndex, endIndex);
|
||||
// 删除指定位置的字符串
|
||||
stringSeed.delete(startIndex, endIndex);
|
||||
|
||||
// 返回被删除的字符串
|
||||
return delectStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于删除字符串池中指定下标的字符串
|
||||
*
|
||||
* @param index 表示用户指定位置
|
||||
* @return 返回被删除的字符串
|
||||
* @see #remove(String)
|
||||
* @see #remove(int, int)
|
||||
*/
|
||||
public String remove(int index) {
|
||||
return remove(index, index);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于移除随机字符串生成范围中重复的字符,以达到范围中字符串不会重复的情况
|
||||
*/
|
||||
public void removeRepetition() {
|
||||
// 判断StringSeed是否为空,为空则返回false
|
||||
if (stringSeed.length() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 用于保存删除重复元素后的字符串
|
||||
StringBuilder newStringSeed = new StringBuilder();
|
||||
// 读取stringSeed中的内容,过滤掉已存在的字符串
|
||||
stringSeed.chars().mapToObj(ch -> String.valueOf((char) ch))
|
||||
.filter(text -> newStringSeed.indexOf(text) < 0)
|
||||
.forEach(newStringSeed::append);
|
||||
|
||||
// 清空StringSeed
|
||||
clear();
|
||||
// 将去重后的字符串放入stringSeed中
|
||||
stringSeed.append(newStringSeed);
|
||||
}
|
||||
|
||||
/**
|
||||
* 以默认方式返回生成的随机字符串
|
||||
* <p>
|
||||
* 默认长度为6个字符,可通过{@link #defaultLength}属性进行修改
|
||||
* </p>
|
||||
*
|
||||
* @return 默认长度的随机字符串
|
||||
* @throws IllegalDataException 当产生字符串不允许重复,且字符串产生范围长度小于默认长度,
|
||||
* 处理方式为{@link RepeatDisposeType#DISPOSE_THROW_EXCEPTION}时抛出的异常
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return toString(defaultLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成随机长度随机字符串,其长度范围由用户指定
|
||||
*
|
||||
* @param stringLengthMin
|
||||
* 随机长度的最小值
|
||||
* @param stringLengthMax
|
||||
* 随机长度的最大值
|
||||
* @param minLength 随机长度的最小值
|
||||
* @param maxLength 随机长度的最大值
|
||||
* @return 返回生成的随机字符串
|
||||
* @see #toString()
|
||||
* @see #toString(int)
|
||||
* @throws IllegalDataException 产生字符串不允许重复,且传入的参数大于字符串产生范围长度,处理方式为抛出异常时抛出
|
||||
* @throws IllegalDataException 当产生字符串不允许重复,且字符串产生范围长度小于默认长度,
|
||||
* 处理方式为{@link RepeatDisposeType#DISPOSE_THROW_EXCEPTION}时抛出的异常
|
||||
*/
|
||||
public String toString(int stringLengthMin, int stringLengthMax) {
|
||||
// 判断随机字符串生成范围是否为空,为空则直接返回空字符串
|
||||
if (stringSeed.length() == 0) {
|
||||
return "";
|
||||
public String toString(int minLength, int maxLength) {
|
||||
// 判断最大生成长度与最小生成长度的关系
|
||||
if (minLength > maxLength) {
|
||||
int temp = minLength;
|
||||
minLength = maxLength;
|
||||
maxLength = temp;
|
||||
}
|
||||
|
||||
// 判断指定的字符串长度是否小于0,如果是,则返回空字符串
|
||||
if (stringLengthMin < 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
// 判断指定的字符串长度最小值是否大于最大值,如果是,则返回空字符串
|
||||
if (stringLengthMax - stringLengthMin < 0) {
|
||||
return "";
|
||||
// 判断最少个数是否小于1
|
||||
if (minLength < 1) {
|
||||
// 再判断最多个数是否大于1,大于1则将最少个数设为1;
|
||||
if (maxLength > 1) {
|
||||
minLength = 1;
|
||||
} else {
|
||||
// 若最少最多的数字都小于1,则返回空集合
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
if ( isRepeat() && stringLengthMax > stringSeed.length() && dispose == DISPOSE_THROW_EXCEPTION ) {
|
||||
throw new IllegalDataException("最大生成长度大于字符串产生范围的长度");
|
||||
//判断两个数值是否一致
|
||||
if (minLength == maxLength) {
|
||||
return toString(minLength);
|
||||
} else {
|
||||
// 返回生成的字符串
|
||||
return toString(new Random().nextInt((maxLength - minLength + 1)) + minLength);
|
||||
}
|
||||
|
||||
return joinString(new Random().nextInt((stringLengthMax - stringLengthMin + 1)) + stringLengthMin); // 返回生成的字符串
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成固定长度的随机字符串,其长度由用户指定
|
||||
*
|
||||
* @param stringLength
|
||||
* 随机字符串的长度
|
||||
* @param stringLength 随机字符串的长度
|
||||
* @return 返回生成的随机字符串
|
||||
* @see #toString()
|
||||
* @see #toString(int, int)
|
||||
* @throws IllegalDataException 产生字符串不允许重复,且传入的参数大于字符串产生范围长度,处理方式为抛出异常时抛出
|
||||
* @throws IllegalDataException 当产生字符串不允许重复,且字符串产生范围长度小于默认长度,
|
||||
* 处理方式为{@link RepeatDisposeType#DISPOSE_THROW_EXCEPTION}时抛出的异常
|
||||
*/
|
||||
public String toString(int stringLength) {
|
||||
// 判断随机字符串生成范围是否为空,为空则直接返回空字符串
|
||||
if (stringSeed.length() == 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
// 判断指定的字符串长度是否小于0,如果是,则返回空字符串
|
||||
if (stringLength < 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return joinString(stringLength); // 返回生成的字符串
|
||||
return createRandomString(stringLength, stringSeed.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* 组装字符串生成范围,用以在不允许出现重复的情况下,对StringSeed进行修改, 在调用该方法时,会先将传参中的字符串拆分为单个字符串,分别进行判断,以
|
||||
* 达到不添加重复字符串的目的
|
||||
*
|
||||
* @param mode
|
||||
* 待添加入StringSeed的字符串
|
||||
* @return 返回字符串添加状态,true为添加成功,false为添加失败
|
||||
*/
|
||||
private void packageString(String mode) {
|
||||
// 循环,将Mode拆分为单个字符串,并分别与StringSeed进行对比,如果某个字符存在,则不添加该字符以保证该字符不会重复添加
|
||||
for (int i = 0; i < mode.length(); i++) {
|
||||
// 判断当前字符是否存在与StringSeed中,如果存在,则继续循环,判断下一个字符
|
||||
if (stringSeed.indexOf(mode.substring(i, i + 1)) > -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 如果不存在拆分的字符,则将字符存入StringSeed中,并将flag定义为true
|
||||
stringSeed.append(mode.substring(i, i + 1));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于生成随机字符串的核心算法
|
||||
* 用于简单返回随机字符串。下标规则可参考{@link #toString(int, int)}方法
|
||||
*
|
||||
* @param stringLength
|
||||
* 指定生成的随机字符串长度
|
||||
* @param minLength 随机长度的最小值
|
||||
* @param maxLength 随机长度的最大值
|
||||
* @param seed 字符串产生范围
|
||||
* @return 返回生成的随机字符串
|
||||
* @see #toString()
|
||||
* @see #toString(int)
|
||||
* @see #toString(int, int)
|
||||
* @throws IllegalDataException 产生字符串不允许重复,且传入的参数大于字符串产生范围长度,处理方式为抛出异常时抛出
|
||||
*/
|
||||
private String joinString(int stringLength) {
|
||||
// 判断字符串字符是否允许重复,不允许重复时其处理方式是否为抛异常,为抛异常时,其stringLength是否大于字符串产生范围的长度,若是,则直接抛出异常
|
||||
if (!isRepeat() && dispose == DISPOSE_THROW_EXCEPTION && stringLength > stringSeed.length()) {
|
||||
throw new IllegalDataException("需要生成的随机字符串长度大于字符串产生范围的最大长度");
|
||||
public static String randomString(int minLength, int maxLength, String seed) {
|
||||
RandomString rs = new RandomString(seed);
|
||||
return rs.toString(minLength, maxLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于简单返回随机字符串。下标规则可参考{@link #toString(int, int)}方法
|
||||
*
|
||||
* @param minLength 随机长度的最小值
|
||||
* @param maxLength 随机长度的最大值
|
||||
* @param stringModes 字符串产生范围,{@link StringMode}枚举对象
|
||||
* @return 返回生成的随机字符串
|
||||
*/
|
||||
public static String randomString(int minLength, int maxLength, StringMode... stringModes) {
|
||||
RandomString rs = new RandomString(stringModes);
|
||||
return rs.toString(minLength, maxLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于向字符串池中添加字符串模型
|
||||
*
|
||||
* @param mode 字符串模型
|
||||
*/
|
||||
private void joinStringSeed(boolean isRepeat, String mode) {
|
||||
// 过滤掉null与空串后,若存在数据,则根据条件,向字符串池中添加数据
|
||||
Optional.ofNullable(mode).filter(text -> !text.isEmpty()).ifPresent(text -> {
|
||||
// 判断传入的参数是否允许字符串池中元素重复,若为true,则等同于调用addMode(StringMode... modes)
|
||||
if (!isRepeat) {
|
||||
// 判断字符串整串是否都在stringSeed中
|
||||
if (stringSeed.indexOf(text) > -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 将字符串拆成单个字符串,分别在stringSeed中进行判断
|
||||
IntStream.range(0, text.length()).mapToObj(text::charAt)
|
||||
// 将char类型转为字符串
|
||||
.map(String::valueOf)
|
||||
// 过滤掉存在于stringSeed中的字符
|
||||
.filter(ch -> stringSeed.indexOf(ch) < 0)
|
||||
.forEach(stringSeed::append);
|
||||
|
||||
} else {
|
||||
stringSeed.append(text);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于根据字符串池,生成随机字符串
|
||||
*
|
||||
* @param length 生成的字符串长度
|
||||
* @param stringSeed 字符串池
|
||||
* @return 生成的随机字符串
|
||||
* @throws IllegalDataException 当产生字符串不允许重复,且字符串产生范围长度小于默认长度,
|
||||
* 处理方式为{@link RepeatDisposeType#DISPOSE_THROW_EXCEPTION}时抛出的异常
|
||||
*/
|
||||
private String createRandomString(int length, String stringSeed) {
|
||||
// 判断需要生成的字符串长度是否小于1位长度
|
||||
if (length < 1) {
|
||||
return "";
|
||||
}
|
||||
|
||||
String RandomString = ""; // 定义一个字符串变量,用于存储选择的字符串
|
||||
int ChooiseNumber = -1; // 定义一个整形变量,用于随机的生成数字,并用于从StringSeed中选择对应的字符
|
||||
Random RandomNumber = new Random(); // 定义一个Random变量,用于生成随机数字
|
||||
// 记录当前是否允许重复
|
||||
boolean isRepeat = repeat;
|
||||
|
||||
//定义循环条件
|
||||
int i = 0;
|
||||
|
||||
//判断是否允许产生的字符串中存在重复的字符
|
||||
if (!isRepeat()) {
|
||||
//定义临时字符串,存储原字符串产生的范围
|
||||
String s = stringSeed.toString();
|
||||
//乱序字符串产生的范围
|
||||
shuffle();
|
||||
|
||||
//判断传入的字符串生成长度是否小于字符串范围的总长度,小于,则按照字符串乱序后截取的方式获取随机字符串,否则, 则读取处理方式
|
||||
if ( stringLength <= stringSeed.length() ) {
|
||||
//截取字符串
|
||||
RandomString = stringSeed.substring(0, stringLength);
|
||||
|
||||
//还原字符串产生范围
|
||||
clear();
|
||||
stringSeed.append(s);
|
||||
return RandomString;
|
||||
} else {
|
||||
//将乱序后的范围赋给RandomString
|
||||
RandomString = stringSeed.toString();
|
||||
//还原字符串产生范围
|
||||
clear();
|
||||
stringSeed.append(s);
|
||||
|
||||
//判断操作方式是否为忽略,若为忽略,则直接返回乱序后的随机字符串
|
||||
if (dispose == DISPOSE_IGNORE) {
|
||||
return RandomString;
|
||||
} else {
|
||||
//若处理方式为重复,则将循环的次数直接加上字符串的长度(等同于循环了N次)
|
||||
i = RandomString.length();
|
||||
}
|
||||
// 判断当前字符串长度是否大于字符串池的最大长度
|
||||
if (length > stringSeed.length() && !isRepeat) {
|
||||
// 若传入的长度大于字符串,且不能重复时,则根据不同的设置做出相应的处理
|
||||
switch (dispose) {
|
||||
case DISPOSE_IGNORE:
|
||||
length = stringSeed.length();
|
||||
break;
|
||||
case DISPOSE_THROW_EXCEPTION:
|
||||
throw new IllegalDataException("需要生成的随机字符串长度大于字符串产生范围的最大长度");
|
||||
case DISPOSE_REPEAT:
|
||||
default:
|
||||
isRepeat = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 循环,在RandomString中放入随机字符,其循环次数决定字符串的长度
|
||||
for (; i < stringLength; i++) {
|
||||
ChooiseNumber = RandomNumber.nextInt(stringSeed.length()); // 从0到StringSeed的总长中随机生成一个数字
|
||||
RandomString = RandomString + stringSeed.charAt(ChooiseNumber); // 将该数字在StringSeed中对应的字符赋给RandomString
|
||||
|
||||
// 存储生成的随机字符串
|
||||
StringBuilder randomString = new StringBuilder();
|
||||
StringBuilder seed = new StringBuilder(stringSeed);
|
||||
Random random = new Random();
|
||||
|
||||
// 循环,生成随机字符串
|
||||
while (randomString.length() < length) {
|
||||
// 根据字符串池的长度,生成随机数
|
||||
int randomNum = random.nextInt(seed.length());
|
||||
randomString.append(seed.charAt(randomNum));
|
||||
|
||||
// 若当前不允许重复,则删除被获取的字符
|
||||
if (!isRepeat) {
|
||||
seed.deleteCharAt(randomNum);
|
||||
}
|
||||
}
|
||||
|
||||
return RandomString; // 返回生成的字符串
|
||||
return randomString.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* <b>文件名:</b>RandomString.java
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>用途:</b> 定义在设置随机字符串不允许出现重复,但需要生成的字符串长度大于随机字符串池的长度时的处理方式
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>编码时间:</b>2021年1月16日下午2:11:36
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>修改时间:</b>2021年1月16日下午2:11:36
|
||||
* </p>
|
||||
*
|
||||
* @author 彭宇琦
|
||||
* @version Ver1.0
|
||||
* @since JDK 1.8
|
||||
*
|
||||
*/
|
||||
public enum RepeatDisposeType {
|
||||
/**
|
||||
* 忽略,只生成一个与随机字符串范围长度相同的随机字符串
|
||||
*/
|
||||
DISPOSE_IGNORE,
|
||||
/**
|
||||
* 抛出异常,中断生成字符串的操作
|
||||
*/
|
||||
DISPOSE_THROW_EXCEPTION,
|
||||
/**
|
||||
* 重复,将随机字符串的生成条件改为允许字符串重复
|
||||
*/
|
||||
DISPOSE_REPEAT;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,135 +0,0 @@
|
|||
package com.auxiliary.tool.data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Random;
|
||||
|
||||
public class RandomWord {
|
||||
/**
|
||||
* 用于存储需要随机返回的词语
|
||||
*/
|
||||
private ArrayList<String> returnWordList = new ArrayList<>();
|
||||
/**
|
||||
* 用于存储默认返回的词语
|
||||
*/
|
||||
private ArrayList<String> conditionWordList = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* 指向生成的词语是否能重复
|
||||
*/
|
||||
private boolean isRepeat = true;
|
||||
|
||||
/**
|
||||
* 用于向无需条件亦可直接返回的词语组中添加词语
|
||||
* @param words 词语组
|
||||
*/
|
||||
public void addRetuenWord(String...words) {
|
||||
returnWordList.addAll(Arrays.asList(words));
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于向无需条件亦可直接返回的词语组中添加词语
|
||||
* @param wordList 词语集合
|
||||
*/
|
||||
public void addRetuenWord(ArrayList<String> wordList) {
|
||||
returnWordList.addAll(wordList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于向符合条件后返回的词语组中添加词语
|
||||
* @param words 词语组
|
||||
*/
|
||||
public void addConditionWord(String...words) {
|
||||
conditionWordList.addAll(Arrays.asList(words));
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于向符合条件后返回的词语组中添加词语
|
||||
* @param wordList 词语集合
|
||||
*/
|
||||
public void addConditionWord(ArrayList<String> wordList) {
|
||||
conditionWordList.addAll(wordList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于设置词语是否可以重复生成
|
||||
* @param isRepeat 词语是否可重复
|
||||
*/
|
||||
public void setRepeat(boolean isRepeat) {
|
||||
this.isRepeat = isRepeat;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于随机生成指定随机个数的词语
|
||||
* @param minLength 最少词语个数
|
||||
* @param maxLength 最多词语个数
|
||||
* @return 生成的词语集合
|
||||
*/
|
||||
public ArrayList<String> toWord(int minLength, int maxLength) {
|
||||
return toWord(getLength(minLength, maxLength));
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于随机生成指定个数的词语
|
||||
* @param length 输出的词语个数
|
||||
* @return 生成的词语集合
|
||||
*/
|
||||
public ArrayList<String> toWord(int length) {
|
||||
//克隆returnWordList,便于对不能生成重复词语的情况下,移除集合中的元素,达到快速返回的目的
|
||||
@SuppressWarnings("unchecked")
|
||||
ArrayList<String> wordList = (ArrayList<String>) returnWordList.clone();
|
||||
|
||||
//存储生成的词语
|
||||
ArrayList<String> randomWordList = new ArrayList<>();
|
||||
//循环,生成相应的词语
|
||||
for (int i = 0; i < length && wordList.size() > 0; i++) {
|
||||
//获取随机下标
|
||||
int index = getRandomIndex(wordList);
|
||||
//存储下标对应的词语
|
||||
randomWordList.add(wordList.get(index));
|
||||
//若生成的词语不可重复,则直接移除wordList中对应的词语
|
||||
if (!isRepeat) {
|
||||
wordList.remove(index);
|
||||
}
|
||||
}
|
||||
|
||||
return randomWordList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于根据词语是否允许重复,返回实际的最大生成词语个数
|
||||
* @param maxLength 设置的最大词语生成个数
|
||||
* @return 实际最大词语生成个数
|
||||
*/
|
||||
private int getLength(int minLength, int maxLength) {
|
||||
//若词语不允许重复生成且minLength大于returnWordList.size(),则将minLength改为returnWordList.size()
|
||||
minLength = (!isRepeat && minLength > returnWordList.size()) ? returnWordList.size() : minLength;
|
||||
//若词语不允许重复生成且maxLength大于returnWordList.size(),则将maxLength改为returnWordList.size()
|
||||
maxLength = (!isRepeat && maxLength > returnWordList.size()) ? returnWordList.size() : maxLength;
|
||||
|
||||
//若两个数字一致,则返回任意一个数字
|
||||
if (minLength == maxLength) {
|
||||
return maxLength;
|
||||
}
|
||||
|
||||
//为避免最小长度与最大长度传参相反,故此处进行一个调换
|
||||
int max = Math.max(minLength, maxLength);
|
||||
int min = Math.min(minLength, maxLength);
|
||||
|
||||
//返回指定长度下的一个随机长度
|
||||
return (new Random().nextInt(max - min + 1) + min);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据指定的集合,返回随机的一个下标
|
||||
* @param wordList 词语集合
|
||||
* @return 集合元素的随机下标
|
||||
*/
|
||||
private int getRandomIndex(ArrayList<String> wordList) {
|
||||
//根据条件获取集合的长度
|
||||
int maxLength = wordList.size();
|
||||
//生成最大长度范围内的随机数
|
||||
return new Random().nextInt(maxLength);
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,193 @@
|
|||
package com.auxiliary.tool.date;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* <b>文件名:</b>InitTimeUtil.java
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>用途:</b> 提供特殊的更改日期/时间的方法,
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>编码时间:</b>2021年1月21日上午8:15:45
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>修改时间:</b>2021年1月21日上午8:15:45
|
||||
* </p>
|
||||
*
|
||||
* @author 彭宇琦
|
||||
* @version Ver1.0
|
||||
* @since JDK 1.8
|
||||
*/
|
||||
public class InitTimeUtil {
|
||||
private InitTimeUtil(){
|
||||
}
|
||||
|
||||
/**
|
||||
* 更改日期为指定日期下当年的第一天
|
||||
* <p>
|
||||
* 例如,指定时间为:2019-12-21 15:21:10,则调用方法后,将返回时间为:2019-01-01 00:00:00
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>注意:</b>若日期未传入(null),则默认为当天的日期
|
||||
* </p>
|
||||
*
|
||||
* @param date 指定的日期
|
||||
* @return 更改的日期
|
||||
*/
|
||||
public static LocalDateTime firstDayOfYear(LocalDateTime date) {
|
||||
date = Optional.ofNullable(date).orElse(LocalDateTime.now());
|
||||
return LocalDateTime.of(date.getYear(), 1, 1, 0, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更改日期为指定日期下当年的最后第一天
|
||||
* <p>
|
||||
* 方法允许指定是否将时间也指向最后的日期,例如:
|
||||
* <ol>
|
||||
* <li>指定时间为:2019-12-21 15:21:10,设置时间指向最后一刻,则返回时间为:2019-12-31 23:59:59</li>
|
||||
* <li>指定时间为:2019-12-21 15:21:10,不设置时间,则返回时间为:2019-12-31 15:21:10</li>
|
||||
* </ol>
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>注意:</b>若日期未传入(null),则默认为当天的日期
|
||||
* </p>
|
||||
*
|
||||
* @param date 指定的日期
|
||||
* @return 更改的日期
|
||||
*/
|
||||
public static LocalDateTime lastDayOfYear(boolean isLastTime, LocalDateTime date) {
|
||||
date = Optional.ofNullable(date).orElse(LocalDateTime.now());
|
||||
return LocalDateTime.of(date.getYear(), 12, 31, isLastTime ? 23 : date.getHour(),
|
||||
isLastTime ? 59 : date.getMinute(), isLastTime ? 59 : date.getSecond());
|
||||
}
|
||||
|
||||
/**
|
||||
* 更改日期为指定日期下当月的第一天
|
||||
* <p>
|
||||
* 例如,指定时间为:2019-12-21 15:21:10,则调用方法后,将返回时间为:2019-12-01 00:00:00
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>注意:</b>若日期未传入(null),则默认为当天的日期
|
||||
* </p>
|
||||
*
|
||||
* @return 更改的日期
|
||||
*/
|
||||
public static LocalDateTime firstDayOfMonth(LocalDateTime date) {
|
||||
date = Optional.ofNullable(date).orElse(LocalDateTime.now());
|
||||
return LocalDateTime.of(date.getYear(), date.getMonth(), 1, 0, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更改日期为指定日期下当月的最后一天
|
||||
* <p>
|
||||
* 方法允许指定是否将时间也指向最后的日期,例如:
|
||||
* <ol>
|
||||
* <li>指定时间为:2019-12-21 15:21:10,设置时间指向最后一刻,则返回时间为:2019-12-31 23:59:59</li>
|
||||
* <li>指定时间为:2019-12-21 15:21:10,不设置时间,则返回时间为:2019-12-31 15:21:10</li>
|
||||
* </ol>
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>注意:</b>若日期未传入(null),则默认为当天的日期
|
||||
* </p>
|
||||
*
|
||||
* @return 更改的日期
|
||||
*/
|
||||
public static LocalDateTime lastDayOfMonth(boolean isLastTime, LocalDateTime date) {
|
||||
date = Optional.ofNullable(date).orElse(LocalDateTime.now());
|
||||
// 设置月份为当前月份的下一月的第一天
|
||||
// 当月份为12月时,使用月份数值加1则会抛出异常,故在异常时设置月份为下一年的第一天即可
|
||||
try {
|
||||
date = LocalDateTime.of(date.getYear(), date.getMonthValue() + 1, 1, isLastTime ? 23 : date.getHour(),
|
||||
isLastTime ? 59 : date.getMinute(), isLastTime ? 59 : date.getSecond());
|
||||
} catch (Exception e) {
|
||||
date = LocalDateTime.of(date.getYear() + 1, 1, 1, isLastTime ? 23 : date.getHour(),
|
||||
isLastTime ? 59 : date.getMinute(), isLastTime ? 59 : date.getSecond());
|
||||
}
|
||||
|
||||
// 将日期减去一天,即可得到本月的最后一天日期
|
||||
return date.minusDays(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更改日期为指定日期下当天的0点
|
||||
* <p>
|
||||
* 例如,指定时间为:2019-12-21 15:21:10,则调用方法后,将返回时间为:2019-12-21 00:00:00
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>注意:</b>若日期未传入(null),则默认为当天的日期
|
||||
* </p>
|
||||
*
|
||||
* @return 更改的日期
|
||||
*/
|
||||
public static LocalDateTime startTimeOfDay(LocalDateTime date) {
|
||||
date = Optional.ofNullable(date).orElse(LocalDateTime.now());
|
||||
return LocalDateTime.of(date.getYear(), date.getMonth(), date.getDayOfMonth(), 0, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更改日期为指定日期下当天的最后一刻
|
||||
* <p>
|
||||
* 例如,指定时间为:2019-12-21 15:21:10,则调用方法后,将返回时间为:2019-12-21 23:59:59
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>注意:</b>若日期未传入(null),则默认为当天的日期
|
||||
* </p>
|
||||
*
|
||||
* @return 更改的日期
|
||||
*/
|
||||
public static LocalDateTime lastTimeOfDay(LocalDateTime date) {
|
||||
date = Optional.ofNullable(date).orElse(LocalDateTime.now());
|
||||
return LocalDateTime.of(date.getYear(), date.getMonth(), date.getDayOfMonth(), 23, 59, 59);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更改日期为指定日期下当天的指定的小时数的起始时间
|
||||
* <p>
|
||||
* 例如,指定时间为:2019-12-21 15:21:10,则调用方法后,将返回时间为:2019-12-21 15:00:00
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>注意:</b>
|
||||
* <ol>
|
||||
* <li>若日期未传入(null),则默认为当天的日期</li>
|
||||
* <li>若传入的小时数大于23或者小于0,则将小时数初始化为指定时间的小时数</li>
|
||||
* </ol>
|
||||
* </p>
|
||||
*
|
||||
* @param hour 指定的小时数
|
||||
* @return 更改的日期
|
||||
*/
|
||||
public static LocalDateTime startHour(int hour, LocalDateTime date) {
|
||||
date = Optional.ofNullable(date).orElse(LocalDateTime.now());
|
||||
if (hour > 23 || hour < 0) {
|
||||
hour = date.getHour();
|
||||
}
|
||||
return LocalDateTime.of(date.getYear(), date.getMonth(), date.getDayOfMonth(), hour, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更改日期为指定日期下当天的指定的分钟数的起始时间
|
||||
* <p>
|
||||
* 例如,指定时间为:2019-12-21 15:21:10,则调用方法后,将返回时间为:2019-12-21 15:21:00
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>注意:</b>
|
||||
* <ol>
|
||||
* <li>若日期未传入(null),则默认为当天的日期</li>
|
||||
* <li>若传入的分钟数大于59或者小于0,则将数值初始化为指定时间的分钟数</li>
|
||||
* </ol>
|
||||
* </p>
|
||||
*
|
||||
* @param hour 指定的分钟数
|
||||
* @return 更改的日期
|
||||
*/
|
||||
public static LocalDateTime startMinute(int minute, LocalDateTime date) {
|
||||
date = Optional.ofNullable(date).orElse(LocalDateTime.now());
|
||||
if (minute > 59 || minute < 0) {
|
||||
minute = date.getMinute();
|
||||
}
|
||||
return LocalDateTime.of(date.getYear(), date.getMonth(), date.getDayOfMonth(), date.getHour(), minute, 0);
|
||||
}
|
||||
}
|
|
@ -1,10 +1,16 @@
|
|||
package com.auxiliary.tool.date;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
|
@ -17,128 +23,183 @@ import java.util.regex.Pattern;
|
|||
* <b>编码时间:</b>2019年12月2日下午5:15:55
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>修改时间:</b>2019年12月2日下午5:15:55
|
||||
* <b>修改时间:</b>2021年1月20日下午12:43:01
|
||||
* </p>
|
||||
*
|
||||
* @author 彭宇琦
|
||||
* @version Ver1.0
|
||||
* @since JDK 12
|
||||
* @since JDK 1.8
|
||||
*
|
||||
*/
|
||||
public class Time {
|
||||
public class Time implements Comparable<Time> {
|
||||
/**
|
||||
* 用于指向指定的时间
|
||||
* 定义默认时区
|
||||
*/
|
||||
private Date date;
|
||||
public static ZoneId defaultZoneId = ZoneId.systemDefault();
|
||||
|
||||
/**
|
||||
* 用于设置的时间,以保证在增加或减少时间后,能还原回初始设置的时间
|
||||
* 指向初始化时设置的时间
|
||||
*/
|
||||
private Date oldDate;
|
||||
private LocalDateTime initTime;
|
||||
/**
|
||||
* 指向根据初始化时间计算后得到的时间
|
||||
*/
|
||||
private LocalDateTime calculateTime;
|
||||
|
||||
/**
|
||||
* 用于存储日期的格式,默认格式为yyyy-MM-dd HH:mm:ss
|
||||
*/
|
||||
private String dateFormat = "yyyy-MM-dd HH:mm:ss";
|
||||
|
||||
private static DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
/**
|
||||
* 定义日期约束类型的传入格式
|
||||
*/
|
||||
private final String REGEX_DATE = "(\\d{4}[-\\.年\\\\/][01]?\\d[-\\.月\\\\/][0123]?\\d日?"
|
||||
+ "( [012]?\\d[:时][0123456]?\\d分?([:分][0123456]?\\d秒?)?)?)|"
|
||||
+ "([012]?\\d[:时][0123456]?\\d分?([:分][0123456]?\\d秒?))";
|
||||
private final static String REGEX_DATE = "(\\D*((\\d{1,2})|(\\d{4}))\\D+\\d{1,2}\\D+\\d{1,2})((\\D+\\d{1,2}){3})?\\D*";
|
||||
|
||||
/**
|
||||
* 构造当前时间
|
||||
* 初始化日期/时间
|
||||
*
|
||||
* @param initTime 日期/时间
|
||||
*/
|
||||
public Time() {
|
||||
setNowTime();
|
||||
private Time(LocalDateTime initTime) {
|
||||
this.initTime = initTime;
|
||||
this.calculateTime = initTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过Date类对象进行构造
|
||||
* 用于根据{@link Date}类对象初始化时间
|
||||
*
|
||||
* @param date Date类对象
|
||||
*/
|
||||
public Time(Date date) {
|
||||
setTime(date);
|
||||
public static Time parse(Date date) {
|
||||
return parse(Optional.ofNullable(date).orElse(new Date()).getTime());
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过时间戳进行构造
|
||||
* 用于根据毫秒数初始化时间
|
||||
*
|
||||
* @param ms 时间戳(毫秒值)
|
||||
*/
|
||||
public Time(long ms) {
|
||||
setTime(ms);
|
||||
public static Time parse(long ms) {
|
||||
// 转换时间戳
|
||||
return new Time(LocalDateTime.ofInstant(Instant.ofEpochMilli(ms), defaultZoneId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过格式化过的时间进行构造
|
||||
* 用于根据已格式化的时间初始化时间
|
||||
*
|
||||
* @param formatTime 已格式化的时间
|
||||
* @throws IncorrectConditionException 时间转换错误时抛出的异常
|
||||
*/
|
||||
public Time(String formatTime) {
|
||||
setTime(formatTime);
|
||||
public static Time parse(String formatTime) {
|
||||
// 判断传入的格式化时间是否符合要求,并将其转换为格式化字符串
|
||||
return parse(formatTime,
|
||||
Optional.ofNullable(formatTime).filter(text -> !text.isEmpty()).filter(text -> text.matches(REGEX_DATE))
|
||||
.map(Time::judgeDateFormatText)
|
||||
.orElseThrow(() -> new IncorrectConditionException("时间“" + formatTime + "”不符合格式的规则")));
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于Date类对象设置指定的时间
|
||||
* 用于根据格式化的日期/时间,及相应的时间格式,初始化日期/时间
|
||||
* <p>
|
||||
* 该方法允许只传入格式化的日期或者时间,如: <code><pre>
|
||||
* Time time1 = Time.parse("2020-12-12", "yyyy-MM-dd");//初始化为2020年12月12日的0点
|
||||
* Time time2 = Time.parse("15:15:15", "HH:mm:ss");//初始化为当天的15时15分15秒
|
||||
* </pre></code>
|
||||
* </p>
|
||||
*
|
||||
* @param date Date类对象
|
||||
* @param formatTime 格式化的日期/时间
|
||||
* @param formatText 时间格式
|
||||
* @return 初始化的类
|
||||
* @throws DateTimeParseException 日期/时间无法转换时抛出的异常
|
||||
*/
|
||||
public void setTime(Date date) {
|
||||
this.date = date;
|
||||
oldDate = this.date;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于根据毫秒数设置指定的时间
|
||||
*
|
||||
* @param ms 时间戳(毫秒值)
|
||||
*/
|
||||
public void setTime(long ms) {
|
||||
date = new Date(ms);
|
||||
oldDate = this.date;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于根据已格式化的时间设置指定的时间
|
||||
*
|
||||
* @param formatTime 已格式化的时间
|
||||
* @throws IncorrectConditionException 时间转换错误时抛出的异常
|
||||
*/
|
||||
public void setTime(String formatTime) {
|
||||
//若formatTime传入为Null或为空串,则设置为当前时间
|
||||
if (formatTime == null || formatTime.isEmpty()) {
|
||||
setNowTime();
|
||||
return;
|
||||
}
|
||||
|
||||
if (formatTime.matches(REGEX_DATE)) {
|
||||
try {
|
||||
date = new SimpleDateFormat(getDateFormat(formatTime)).parse(formatTime);
|
||||
oldDate = this.date;
|
||||
} catch (ParseException e) {
|
||||
public static Time parse(String formatTime, String formatText) {
|
||||
// 定义相应的时间格式,并用于解析传入的时间
|
||||
dateFormat = DateTimeFormatter.ofPattern(formatText);
|
||||
try {
|
||||
return new Time(LocalDateTime.parse(formatTime, dateFormat));
|
||||
} catch (DateTimeParseException e) {
|
||||
if (formatText.matches(".*M+.*")) {
|
||||
return new Time(LocalDate.parse(formatTime, dateFormat).atStartOfDay());
|
||||
} else {
|
||||
return new Time(LocalTime.parse(formatTime, dateFormat).atDate(LocalDate.now()));
|
||||
}
|
||||
} else {
|
||||
throw new IncorrectConditionException("时间“" + formatTime + "”不符合格式的规则");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于将时间设置为当前时间
|
||||
* 用于根据{@link LocalDateTime}对象初始化日期/时间,若未传入时间或时间写入有误,则初始化为当前时间
|
||||
*
|
||||
* @param dateTime 指定的{@link LocalDateTime}对象
|
||||
*/
|
||||
public void setNowTime() {
|
||||
date = new Date();
|
||||
oldDate = this.date;
|
||||
public static Time parse(LocalDateTime dateTime) {
|
||||
return new Time(Optional.ofNullable(dateTime).orElse(LocalDateTime.now()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 用于将时间初始化为当前时间
|
||||
*/
|
||||
public static Time parse() {
|
||||
return new Time(LocalDateTime.now());
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于对日期/时间中的指定单位进行赋值
|
||||
* @param timeNum 指定的数值
|
||||
* @param timeUnit 时间单位枚举{@link TimeUnit}
|
||||
* @return 类本身
|
||||
* @throws IncorrectConditionException 数值无法被赋入相应的单位下时抛出的异常
|
||||
*/
|
||||
public Time setTime(int timeNum, TimeUnit timeUnit) {
|
||||
//记录每个时间下的数值
|
||||
int year = calculateTime.getYear();
|
||||
int month = calculateTime.getMonthValue();
|
||||
int day = calculateTime.getDayOfMonth();
|
||||
int hour = calculateTime.getHour();
|
||||
int minute = calculateTime.getMinute();
|
||||
int second = calculateTime.getSecond();
|
||||
|
||||
//根据枚举,对相应的日期进行赋值
|
||||
switch (timeUnit) {
|
||||
case YEAR:
|
||||
year = timeNum;
|
||||
break;
|
||||
case MONTH:
|
||||
month = timeNum;
|
||||
break;
|
||||
case DAY:
|
||||
day = timeNum;
|
||||
break;
|
||||
case HOUR:
|
||||
hour = timeNum;
|
||||
break;
|
||||
case MINUTE:
|
||||
minute = timeNum;
|
||||
break;
|
||||
case SECOND:
|
||||
second = timeNum;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
//格式化时间,若时间无法被写入,则抛出IncorrectConditionException异常
|
||||
try {
|
||||
calculateTime = LocalDateTime.of(year, month, day, hour, minute, second);
|
||||
} catch (Exception e) {
|
||||
throw new IncorrectConditionException(
|
||||
String.format("不存在的日期:%d-%d-%d %d:%d:%d", year, month, day, hour, minute, second), e);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置返回时间的格式,该方法可传入时间格式,亦可向该方法中传入时间格式的模板,
|
||||
* 通过识别模板得到日期的格式,但作为模板的日期也必须满足时间格式。例如:<br>
|
||||
* <pre><code>
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* Time time = new Time(1575387800000L);
|
||||
*
|
||||
* time.setTimeFormat("yyyy年MM月dd日 HH:mm:ss");
|
||||
|
@ -146,20 +207,35 @@ public class Time {
|
|||
*
|
||||
* time.setTimeFormat("2019/12/04 03:03:20");
|
||||
* getFormatTime();//输出:2019/12/03 23:43:20
|
||||
* </code></pre>
|
||||
* 注意,传入已格式化的时间时,其不会改变当前存储的时间
|
||||
* </code>
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* <b>注意</b>
|
||||
* <ol>
|
||||
* <li>传入已格式化的时间时,其不会改变当前存储的时间</li>
|
||||
* <li>已格式化的时间中,其分隔符不能包含字母,否则转译将出错(在格式化时间的方法中也不允许存在字母)</li>
|
||||
* </ol>
|
||||
* </p>
|
||||
*
|
||||
* @param pattern 指定的格式或已格式化的时间
|
||||
*/
|
||||
public void setTimeFormat(String pattern) {
|
||||
public Time setTimeFormat(String pattern) {
|
||||
pattern = Optional.ofNullable(pattern).filter(text -> !text.isEmpty())
|
||||
.orElseThrow(() -> new IncorrectConditionException("未指定时格式"));
|
||||
|
||||
if (pattern.matches(REGEX_DATE)) {
|
||||
dateFormat = getDateFormat(pattern);
|
||||
} else {
|
||||
try {
|
||||
dateFormat = pattern;
|
||||
} catch (IllegalArgumentException e) {
|
||||
dateFormat = DateTimeFormatter.ofPattern(judgeDateFormatText(pattern));
|
||||
} catch (IncorrectConditionException e) {
|
||||
// 若转换时出现异常,则按照基本的方式进行转换
|
||||
dateFormat = DateTimeFormatter.ofPattern(pattern);
|
||||
}
|
||||
} else {
|
||||
dateFormat = DateTimeFormatter.ofPattern(pattern);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -168,18 +244,7 @@ public class Time {
|
|||
* @return Date类对象
|
||||
*/
|
||||
public Date getDate() {
|
||||
return date;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于返回Calendar类对象
|
||||
* @return Calendar类对象
|
||||
*/
|
||||
public Calendar getCalendar() {
|
||||
Calendar c = Calendar.getInstance();
|
||||
c.setTime(date);
|
||||
|
||||
return c;
|
||||
return Date.from(calculateTime.atZone(defaultZoneId).toInstant());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -187,321 +252,349 @@ public class Time {
|
|||
*
|
||||
* @return 时间戳
|
||||
*/
|
||||
public long getTime() {
|
||||
return date.getTime();
|
||||
public long getMilliSecond() {
|
||||
return calculateTime.atZone(defaultZoneId).toInstant().toEpochMilli();
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于返回设置时间的格式化后的时间,若通过{@link #Time(String)}构造
|
||||
* 或{@link #setTime(String)}方法创建的时间,则按照原格式进行返回,若 通过其他方法 创建的时间,则按照默认的“yyyy-MM-dd
|
||||
* HH:mm:ss”格式进行返回
|
||||
* 用于以指定的格式返回格式化后的时间。
|
||||
* <p>
|
||||
* 若未设置时间格式,则默认按照“yyyy-MM-dd HH:mm:ss”的格式进行返回
|
||||
* </p>
|
||||
*
|
||||
* @return 格式化后的时间
|
||||
*/
|
||||
public String getFormatTime() {
|
||||
return new SimpleDateFormat(dateFormat).format(date);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于还原最后一次设置的时间
|
||||
*/
|
||||
public void initTime() {
|
||||
date = oldDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 用于根据传入的增减时间的规则对时间进行增减,传入需要修改的时间单位,
|
||||
* 根据单位前的数值对单位进行增减。例如:需要对当前设置的时间增加1年3个月又5天并较少2小时30分钟45秒,
|
||||
* 此时可以传入“1年3月5日-2时-30分-45秒”,亦可以传入“1y3m5d-2h-30min-45s”。
|
||||
* </p>
|
||||
* <p>
|
||||
* 注意:
|
||||
* <ol>
|
||||
* <li>单位必须准确,允许传入以下单位:
|
||||
* <ul>
|
||||
* <li>年单位:年、y、Y</li>
|
||||
* <li>月单位:月、m、M</li>
|
||||
* <li>周单位:周、w、W</li>
|
||||
* <li>日单位:日、d、D</li>
|
||||
* <li>小时单位:时、h、H</li>
|
||||
* <li>分钟单位:分、min、MIN</li>
|
||||
* <li>秒单位:秒、s、S</li>
|
||||
* </ul>
|
||||
* </li>
|
||||
* <li>允许传入小数,但年、月传入小数时,按照自然年及自然月计算,即1年365天,不考虑闰年;
|
||||
* 1月30天,不考虑大月与二月。例如,传入5.3y2.5h则,5.3年转换为5.3 * 365天计算,
|
||||
* 2.5小时将转化为增加2.5 * 60分钟计算。建议不要在年、月中传入小数,否则可能导致计算失真
|
||||
* </li>
|
||||
* </ol>
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @param regex 时间规则
|
||||
* @return 返回修改后的时间戳
|
||||
*/
|
||||
public long addTime(String regex) {
|
||||
//去空格
|
||||
regex = regex.replaceAll(" ", "");
|
||||
|
||||
// 初始化Calendar类,用于修改日期
|
||||
Calendar cTime = Calendar.getInstance();
|
||||
cTime.setTime(date);
|
||||
|
||||
//封装传入的修改时间规则,以便于删除已修改的规则
|
||||
StringBuilder time = new StringBuilder(regex);
|
||||
//用于指向规则中单位的位置
|
||||
int index = -1;
|
||||
|
||||
// 判断是否包含分钟,由于分钟比较特殊,可能会与月份重复,故放在第一位判断;
|
||||
//若存在小数点,则按照毫秒进行转换
|
||||
if ((index = time.indexOf("分")) > -1 || (index = time.indexOf("min")) > -1
|
||||
|| (index = time.indexOf("MIN")) > -1) {
|
||||
//存储待判断单位前的字符串
|
||||
String subTime = time.substring(0, index);
|
||||
//存储待判断单位前数值位置
|
||||
int numIndex = getIndex(time.substring(0, index));
|
||||
|
||||
//转换数值
|
||||
int addTime = (int) (Double.valueOf(subTime.substring(numIndex)) * 60.0);
|
||||
//cTime增加相应日期
|
||||
cTime.add(Calendar.SECOND, addTime);
|
||||
|
||||
//删除已修改的单位以及其数值,由于分钟单位可能为三位,故需要根据具体传入的单位来定义
|
||||
time = time.delete(numIndex,
|
||||
time.substring(index, time.length()).indexOf("分") == 0 ? index + 1 : index + 3);
|
||||
}
|
||||
|
||||
//判断是否包含年份,若存在小数点,则忽略
|
||||
if ((index = time.indexOf("年")) > -1 || (index = time.indexOf("y")) > -1 || (index = time.indexOf("Y")) > -1) {
|
||||
//存储待判断单位前的字符串
|
||||
String subTime = time.substring(0, index);
|
||||
//存储待判断单位前数值位置
|
||||
int numIndex = getIndex(time.substring(0, index));
|
||||
|
||||
//转换数值
|
||||
int addTime = 0;
|
||||
String yearNum = subTime.substring(numIndex);
|
||||
try {
|
||||
//若传入的年份是整数,则直接按照整数转换,并对年份增加相应的数值
|
||||
addTime = Integer.valueOf(yearNum);
|
||||
cTime.add(Calendar.YEAR, addTime);
|
||||
}catch (NumberFormatException e) {
|
||||
//若年份包含小数,则按照小数点进行切分,先对年份的整数部分进行增加
|
||||
String[] num = yearNum.split("\\.");
|
||||
addTime = Integer.valueOf(num[0]);
|
||||
cTime.add(Calendar.YEAR, addTime);
|
||||
|
||||
//之后对小数部分拼接“0.”,转换为double,之后将其转换成天数
|
||||
int remainder = (int) (Double.valueOf((addTime > 0 ? "0.": "-0.") + num[1]) * 365.0);
|
||||
cTime.add(Calendar.DATE, remainder);
|
||||
}
|
||||
|
||||
//删除已修改的单位以及其数值
|
||||
time = time.delete(numIndex, index + 1);
|
||||
}
|
||||
|
||||
//判断是否包含月份,若存在小数点,则忽略
|
||||
if ((index = time.indexOf("月")) > -1 || (index = time.indexOf("m")) > -1 || (index = time.indexOf("M")) > -1) {
|
||||
//存储待判断单位前的字符串
|
||||
String subTime = time.substring(0, index);
|
||||
//存储待判断单位前数值位置
|
||||
int numIndex = getIndex(time.substring(0, index));
|
||||
|
||||
//转换数值
|
||||
int addTime = 0;
|
||||
String monthNum = subTime.substring(numIndex);
|
||||
try {
|
||||
//若传入的年份是整数,则直接按照整数转换,并对年份增加相应的数值
|
||||
addTime = Integer.valueOf(monthNum);
|
||||
cTime.add(Calendar.MONTH, addTime);
|
||||
}catch (NumberFormatException e) {
|
||||
//若年份包含小数,则按照小数点进行切分,先对年份的整数部分进行增加
|
||||
String[] num = monthNum.split("\\.");
|
||||
addTime = Integer.valueOf(num[0]);
|
||||
cTime.add(Calendar.MONTH, addTime);
|
||||
|
||||
//之后对小数部分拼接“0.”,转换为double,之后将其转换成天数
|
||||
addTime = (int) (Double.valueOf((addTime > 0 ? "0.": "-0.") + num[1]) * 30.0);
|
||||
cTime.add(Calendar.DATE, addTime);
|
||||
}
|
||||
|
||||
//删除已修改的单位以及其数值
|
||||
time = time.delete(numIndex, index + 1);
|
||||
}
|
||||
|
||||
//判断是否包含月份,若存在小数点,则忽略
|
||||
if ((index = time.indexOf("周")) > -1 || (index = time.indexOf("w")) > -1 || (index = time.indexOf("W")) > -1) {
|
||||
//存储待判断单位前的字符串
|
||||
String subTime = time.substring(0, index);
|
||||
//存储待判断单位前数值位置
|
||||
int numIndex = getIndex(time.substring(0, index));
|
||||
|
||||
//转换数值
|
||||
int addTime = (int) (Double.valueOf(subTime.substring(numIndex)) * 7.0);
|
||||
//cTime增加相应日期
|
||||
cTime.add(Calendar.DATE, addTime);
|
||||
|
||||
//删除已修改的单位以及其数值
|
||||
time = time.delete(numIndex, index + 1);
|
||||
}
|
||||
|
||||
//判断是否包含天数,若存在小数点,则忽略
|
||||
if ((index = time.indexOf("日")) > -1 || (index = time.indexOf("d")) > -1 || (index = time.indexOf("D")) > -1) {
|
||||
//存储待判断单位前的字符串
|
||||
String subTime = time.substring(0, index);
|
||||
//存储待判断单位前数值位置
|
||||
int numIndex = getIndex(time.substring(0, index));
|
||||
|
||||
//转换数值
|
||||
int addTime = (int) (Double.valueOf(subTime.substring(numIndex)) * 24.0 * 60.0 * 60.0);
|
||||
//cTime增加相应日期
|
||||
cTime.add(Calendar.SECOND, addTime);
|
||||
|
||||
//删除已修改的单位以及其数值
|
||||
time = time.delete(numIndex, index + 1);
|
||||
}
|
||||
|
||||
//判断是否包含小时,若存在小数点,则按照毫秒进行转换
|
||||
if ((index = time.indexOf("时")) > -1 || (index = time.indexOf("h")) > -1 || (index = time.indexOf("H")) > -1) {
|
||||
//存储待判断单位前的字符串
|
||||
String subTime = time.substring(0, index);
|
||||
//存储待判断单位前数值位置
|
||||
int numIndex = getIndex(time.substring(0, index));
|
||||
|
||||
//转换数值
|
||||
int addTime = (int) (Double.valueOf(subTime.substring(numIndex)) * 60.0 * 60.0);
|
||||
//cTime增加相应日期
|
||||
cTime.add(Calendar.SECOND, addTime);
|
||||
|
||||
//删除已修改的单位以及其数值
|
||||
time = time.delete(numIndex, index + 1);
|
||||
}
|
||||
|
||||
//判断是否包含秒,若存在小数点,则按照毫秒进行转换
|
||||
if ((index = time.indexOf("秒")) > -1 || (index = time.indexOf("s")) > -1 || (index = time.indexOf("S")) > -1) {
|
||||
//存储待判断单位前的字符串
|
||||
String subTime = time.substring(0, index);
|
||||
//存储待判断单位前数值位置
|
||||
int numIndex = getIndex(time.substring(0, index));
|
||||
|
||||
//转换数值
|
||||
int addTime = (int) (Double.valueOf(subTime.substring(numIndex)) * 1.0);
|
||||
//cTime增加相应日期
|
||||
cTime.add(Calendar.SECOND, addTime);
|
||||
|
||||
//删除已修改的单位以及其数值
|
||||
time = time.delete(numIndex, index + 1);
|
||||
}
|
||||
|
||||
//将转换后的时间存储至date中
|
||||
date = cTime.getTime();
|
||||
|
||||
return getTime();
|
||||
return calculateTime.format(dateFormat);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改原始存储的时间,返回修改后的时间戳,且不影响原存储的时间,具体修改规则可以参见{@link #addTime(String)}
|
||||
* 用于以{@link LocalDateTime}类对象的形式,返回计算后的日期/时间
|
||||
* @return {@link LocalDateTime}类对象
|
||||
*/
|
||||
public LocalDateTime getLocalDateTime() {
|
||||
return LocalDateTime.of(calculateTime.toLocalDate(), calculateTime.toLocalTime());
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于以{@link Time}的形式返回初始化时设置的时间
|
||||
* @return 始化时设置的时间
|
||||
*/
|
||||
public Time getInitTime() {
|
||||
return Time.parse(initTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于以{@link Time}的形式将设置后的时间作为初始时间进行返回
|
||||
* @return 始化时设置的时间
|
||||
*/
|
||||
public Time getCalculateTime() {
|
||||
return Time.parse(calculateTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于还原初始化时设置的日期/时间
|
||||
*/
|
||||
public Time initTime() {
|
||||
calculateTime = initTime;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于根据条件计算日期/时间,方法允许传入小数与负数进行计算
|
||||
* <p>
|
||||
* <b>注意:</b>在计算年、月时,若传入的数值是小数,在转换毫秒值时,其会按照
|
||||
* <ul>
|
||||
* <li>1年 = 365天</li>
|
||||
* <li>1月 = 30天</li>
|
||||
* </ul>
|
||||
* 进行计算,在跨度大的计算中,其会存在精度的丢失
|
||||
* </p>
|
||||
*
|
||||
* @param num 日期/时间增减的数量
|
||||
* @param timeUnit 日期计算的单位
|
||||
*/
|
||||
public Time addTime(double num, TimeUnit timeUnit) {
|
||||
calculateTime = calcuLocalTime(Double.valueOf(num), timeUnit, calculateTime);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于根据传入的增减时间的规则对时间进行增减。
|
||||
* <p>
|
||||
* 根据单位前的数值对指定的单位进行增减。例如:需要对当前设置的时间增加1年3个月又5天并较少2小时30分钟45秒,
|
||||
* 此时可以传入“1年3月5日-2时-30分-45秒”,亦可以传入“1y3m5d-2h-30min-45s”。
|
||||
* <ul>
|
||||
* 可传入的单位有:
|
||||
* <li>年单位:年、y、Y</li>
|
||||
* <li>月单位:月、m、M</li>
|
||||
* <li>周单位:周、w、W</li>
|
||||
* <li>日单位:日、d、D</li>
|
||||
* <li>小时单位:时、h、H</li>
|
||||
* <li>分钟单位:分、min、MIN</li>
|
||||
* <li>秒单位:秒、s、S</li>
|
||||
* </ul>
|
||||
* 具体的计算规则与{@link #addTime(double, TimeUnit)}方法一致
|
||||
* </p>
|
||||
* @param regex 时间规则
|
||||
* @return 返回修改后的时间戳
|
||||
* @see #addTime(String)
|
||||
*/
|
||||
public long addOldTime(String regex) {
|
||||
//TODO 此处逻辑需要修改
|
||||
long time = addTime(regex);
|
||||
initTime();
|
||||
public Time addTime(String calculateTimeText) {
|
||||
// 将字符串转换为char[]数组
|
||||
char[] chars = Optional.ofNullable(calculateTimeText).filter(text -> !text.isEmpty())
|
||||
// 为保证最后一位能进行计算,在字符串末尾拼接一个“-”符号
|
||||
.map(text -> text + "-").map(String::toCharArray)
|
||||
.orElseThrow(() -> new IncorrectConditionException("必须指定修改时间的参数"));
|
||||
|
||||
// 记录当前计算的时间
|
||||
LocalDateTime nowTime = calculateTime;
|
||||
|
||||
/*
|
||||
* 判断单位思路: 1.遍历通过calculateTimeText得到的每一个字符 2.判断当前字符是否为数字:
|
||||
* a.若为数字,则判断上一次读取的内容是否为字符: I.若为字符,则表示上一个单位及计算数值已读取完毕,则先对上一次的数值对日期时间进行一次计算
|
||||
* II.若为数字,则表示当前正在读取计算的数值,则不进行操作 判断结束后,记录isUnit为false,表示当前字符为数字,并拼接到numText中
|
||||
* b.若为非数字,则将isUnit设置为true,并拼接计算单位
|
||||
*/
|
||||
// 遍历所有的字符,区别存储单位与增减的数值
|
||||
StringBuilder numText = new StringBuilder();
|
||||
StringBuilder unitText = new StringBuilder();
|
||||
boolean isUnit = false;
|
||||
for (char ch : chars) {
|
||||
// 判断当前字符是否为数字
|
||||
if (Character.isDigit(ch) || ch == '.' || ch == '-') {
|
||||
// 判断上一次读取的内容是否为字符
|
||||
if (isUnit) {
|
||||
nowTime = calcuLocalTime(disposeDoubleText(numText.toString()),
|
||||
Arrays.stream(TimeUnit.values()).filter(unit -> unit.isTimeUnit(unitText.toString()))
|
||||
.findFirst().orElseThrow(
|
||||
() -> new IncorrectConditionException("无法识别的计算公式:" + numText + unitText)),
|
||||
nowTime);
|
||||
|
||||
numText.delete(0, numText.length());
|
||||
unitText.delete(0, unitText.length());
|
||||
}
|
||||
|
||||
numText.append(ch);
|
||||
isUnit = false;
|
||||
} else {
|
||||
isUnit = true;
|
||||
unitText.append(ch);
|
||||
}
|
||||
}
|
||||
|
||||
calculateTime = nowTime;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于对计算的double数值进行处理,不全小数点前后缺失的内容
|
||||
*
|
||||
* @param doubleText 数值文本
|
||||
* @return 转换后的double类型
|
||||
*/
|
||||
private Double disposeDoubleText(String doubleText) {
|
||||
int index = doubleText.indexOf(".");
|
||||
if (index == doubleText.length() - 1) {
|
||||
return Double.valueOf(doubleText + "0");
|
||||
} else if (index == 0) {
|
||||
return Double.valueOf("0" + doubleText);
|
||||
} else {
|
||||
return Double.valueOf(doubleText);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于对传入的时间进行计算,并返回计算结果
|
||||
*
|
||||
* @param num 计算数值
|
||||
* @param timeUnit 计算单位
|
||||
* @param time 指定的日期
|
||||
* @return 计算后得到的日期
|
||||
*/
|
||||
private LocalDateTime calcuLocalTime(Double num, TimeUnit timeUnit, LocalDateTime time) {
|
||||
// 为避免出现数字过大导致计算出错的问题,先计算整数部分,再将小数部分转换为时间戳后,计算毫秒值
|
||||
time = time.plus(num.intValue(), timeUnit.getChronoUnit());
|
||||
num = num - num.intValue();
|
||||
time = time.plus((long) (num * timeUnit.getToMillisNum()), ChronoUnit.MILLIS);
|
||||
|
||||
return time;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于识别传入的日期文本,并将日期文本转换为相应的日期格式化字符串
|
||||
* <p>
|
||||
* <b>注意:</b>
|
||||
* <ol>
|
||||
* <li>日期字符串必须是三位完整的日期(X年X月X日)或时间(X时X分X秒),或者是完整的日期+时间(X年X月X日X时X分X秒)</li>
|
||||
* <li>日期字符串前后允许添加非数字字符</li>
|
||||
* <li>无法识别纯数字的日期格式</li>
|
||||
* </ol>
|
||||
* </p>
|
||||
*
|
||||
* @param dateText 日期文本
|
||||
* @return 相应的日期格式化字符串
|
||||
*/
|
||||
private static String judgeDateFormatText(String dateText) {
|
||||
// 判断格式化日期时间中是否存在字母
|
||||
if (dateText.matches(".*[a-zA-Z]+.*")) {
|
||||
throw new IncorrectConditionException("格式化的日期/时间中存在字母:" + dateText);
|
||||
}
|
||||
|
||||
// 将传入的日期文本转换为字符数组
|
||||
char[] chars = dateText.toCharArray();
|
||||
|
||||
/*
|
||||
* 转换思路: 1.遍历通过dateText得到的每一个字符 2.判断当前字符是否为数字:
|
||||
* a.若为数字,则记录isSign为false,表示当前字符为数字,并拼接index指向的位数
|
||||
* b.若为非数字,则记录isSign为true,表示当前字符为字符,则需要再次判断上一个字符是 否也是非数字(即isSign是否本身为false):
|
||||
* I.若上一个字符不为非数字(isSign原为true),则设置index指向的位数加1(即第一次读取到分隔符, 表示上一位的日期以存储完毕)
|
||||
* II.若上一位为非数字(isSign原为false),则不做改动(即该字符仅为分隔符的一部分) 判断结束后,将isSign设置为true,并拼接分隔符
|
||||
* 3.结束循环后,得到一个待转译的中间字符串
|
||||
*
|
||||
* 举例:传入“2020-12-25 14:12:12”最终会转换为“1111-22-33 44:55:66”
|
||||
*/
|
||||
int index = 1;
|
||||
boolean isSign = false;
|
||||
StringBuilder formatTextBuilder = new StringBuilder();
|
||||
for (char ch : chars) {
|
||||
if (Character.isDigit(ch)) {
|
||||
isSign = false;
|
||||
formatTextBuilder.append(index);
|
||||
} else {
|
||||
if (!isSign) {
|
||||
index++;
|
||||
}
|
||||
|
||||
isSign = true;
|
||||
formatTextBuilder.append(ch);
|
||||
}
|
||||
}
|
||||
|
||||
// 判断中间字符串最后一位是否为非数字字符,若为非数字字符,表示位数多移动了1位,需要减1后得到真实的位数
|
||||
index -= (formatTextBuilder.substring(formatTextBuilder.length() - 1).matches("\\d") ? 0 : 1);
|
||||
|
||||
// 判断位数,若位数为3,则表示只传入了日期或者时间
|
||||
if (index == 3) {
|
||||
// 若第一位包含4个字符,则按日期转换,否则按时间转换
|
||||
if (formatTextBuilder.substring(formatTextBuilder.indexOf("1"), formatTextBuilder.lastIndexOf("1") + 1)
|
||||
.length() == 4) {
|
||||
return formatTextBuilder.toString().replaceAll("1", "y").replaceAll("2", "M").replaceAll("3", "d");
|
||||
} else {
|
||||
return formatTextBuilder.toString().replaceAll("1", "H").replaceAll("2", "m").replaceAll("3", "s");
|
||||
}
|
||||
} else if (index == 6) {
|
||||
// 若位数为6,表示既传入了日期也传入了时间
|
||||
return formatTextBuilder.toString().replaceAll("1", "y").replaceAll("2", "M").replaceAll("3", "d")
|
||||
.replaceAll("4", "H").replaceAll("5", "m").replaceAll("6", "s");
|
||||
} else {
|
||||
throw new IncorrectConditionException("时间“" + dateText + "”不符合格式的规则");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Time compateTime) {
|
||||
return Optional.ofNullable(compateTime)
|
||||
.map(Time::getLocalDateTime)
|
||||
.map(calculateTime::compareTo)
|
||||
.orElseThrow(() -> new IncorrectConditionException("需要比较的时间存在异常"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getFormatTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((calculateTime == null) ? 0 : calculateTime.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
Time other = (Time) obj;
|
||||
if (calculateTime == null) {
|
||||
if (other.calculateTime != null)
|
||||
return false;
|
||||
} else if (!calculateTime.equals(other.calculateTime))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于判断相应单位前的数字在整个字符串中所存在的位置
|
||||
* @param text 传入的除当前判断单位前的字符串,例如有规则5H31s,判断秒数,则传入5H31
|
||||
* @return 返回待判断单位前的数值,如5H31s,判断秒数,则返回2
|
||||
* 用于根据最小比较单位,对时间进行比较
|
||||
* <p>
|
||||
* 通过指定最小比较单位,从而返回该单位及以上单位的对比结果,例如:
|
||||
* <ul>
|
||||
* 假定有如下两个日期:
|
||||
* <code><pre>
|
||||
* Time t1 = Time.parse("2020-12-10 17:22:12");
|
||||
* Time t2 = Time.parse("2020-12-10 20:27:12");
|
||||
* </pre></code>
|
||||
* <li>当调用{@code t1.equalsForUnit(t2, TimeUnit.SECOND)}时,则返回结果为false</li>
|
||||
* <li>当调用{@code t1.equalsForUnit(t2, TimeUnit.DAY)}时,则返回结果为true</li>
|
||||
* </ul>
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>注意:</b>除{@link TimeUnit#YEAR}、{@link TimeUnit#MONTH}、{@link TimeUnit#DAY}、
|
||||
* {@link TimeUnit#HOUR}、{@link TimeUnit#MINUTE}、{@link TimeUnit#SECOND}单位外,其他的
|
||||
* 单位传入进行判断时,会抛出异常
|
||||
* </p>
|
||||
* @param compareTime 需要比对的时间
|
||||
* @param timeUnit 最小判断单位
|
||||
* @return 对比结果
|
||||
* @throws IncorrectConditionException 单位传入有误时抛出的异常
|
||||
*/
|
||||
private static int getIndex(String text) {
|
||||
// 定义规则
|
||||
String regex = "(\\.\\d+)|(-?\\d+(\\.\\d+)?)";
|
||||
|
||||
// 如果其本身符合正则,则返回0
|
||||
if (text.matches(regex)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 若本身不符合正则,则从后向前对字符串逐个增加,直到找到下一个单位为止,返回其在字符串中相应的位置
|
||||
for (int i = 1; i < text.length(); i++) {
|
||||
int index = text.length() - i;
|
||||
// 若切分到的字符串不再符合正则,即此时已找到下一个单位,则返回其下标+1
|
||||
// 例如,有字符串5H31s,传入到方法中的字符串将为5H31
|
||||
// 逐个累加字符串时,将读取到H31,此时正则返回false,则记录其下标+1,即为3的位置
|
||||
if (!text.substring(index).matches(regex)) {
|
||||
return index + 1;
|
||||
}
|
||||
public boolean equalsForUnit(Time compareTime, TimeUnit timeUnit) {
|
||||
if (compareTime == null || timeUnit == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//若判断失败,则返回-1,理论上不存在该返回
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 识别传入的时间格式
|
||||
*
|
||||
* @param time 时间
|
||||
* @return 时间格式
|
||||
*/
|
||||
private String getDateFormat(String time) {
|
||||
boolean year = false;
|
||||
Pattern pattern = Pattern.compile("^[-\\+]?[\\d]*$");
|
||||
if (pattern.matcher(time.substring(0, 4)).matches()) {
|
||||
year = true;
|
||||
boolean result = equals(compareTime);
|
||||
//若两时间一致,则直接返回true
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int index = 0;
|
||||
if (!year) {
|
||||
if (time.contains("月") || time.contains("-") || time.contains("/")) {
|
||||
if (Character.isDigit(time.charAt(0))) {
|
||||
index = 1;
|
||||
}
|
||||
} else {
|
||||
index = 3;
|
||||
|
||||
switch (timeUnit) {
|
||||
case SECOND:
|
||||
result = (compareTime.getLocalDateTime().getSecond() == calculateTime.getSecond());
|
||||
if (!result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < time.length(); i++) {
|
||||
char chr = time.charAt(i);
|
||||
if (Character.isDigit(chr)) {
|
||||
if (index == 0) {
|
||||
sb.append("y");
|
||||
}
|
||||
if (index == 1) {
|
||||
sb.append("M");
|
||||
}
|
||||
if (index == 2) {
|
||||
sb.append("d");
|
||||
}
|
||||
if (index == 3) {
|
||||
sb.append("H");
|
||||
}
|
||||
if (index == 4) {
|
||||
sb.append("m");
|
||||
}
|
||||
if (index == 5) {
|
||||
sb.append("s");
|
||||
}
|
||||
if (index == 6) {
|
||||
sb.append("S");
|
||||
}
|
||||
} else {
|
||||
if (i > 0) {
|
||||
char lastChar = time.charAt(i - 1);
|
||||
if (Character.isDigit(lastChar)) {
|
||||
index++;
|
||||
}
|
||||
}
|
||||
sb.append(chr);
|
||||
case MINUTE:
|
||||
result = (compareTime.getLocalDateTime().getMinute() == calculateTime.getMinute());
|
||||
if (!result) {
|
||||
return result;
|
||||
}
|
||||
case HOUR:
|
||||
result = (compareTime.getLocalDateTime().getHour() == calculateTime.getHour());
|
||||
if (!result) {
|
||||
return result;
|
||||
}
|
||||
case DAY:
|
||||
result = (compareTime.getLocalDateTime().getDayOfMonth() == calculateTime.getDayOfMonth());
|
||||
if (!result) {
|
||||
return result;
|
||||
}
|
||||
case MONTH:
|
||||
result = (compareTime.getLocalDateTime().getMonth() == calculateTime.getMonth());
|
||||
if (!result) {
|
||||
return result;
|
||||
}
|
||||
case YEAR:
|
||||
result = (compareTime.getLocalDateTime().getYear() == calculateTime.getYear());
|
||||
return result;
|
||||
default:
|
||||
throw new IncorrectConditionException("无法比较的单位:" + timeUnit);
|
||||
}
|
||||
|
||||
// 存储转换后的格式
|
||||
dateFormat = sb.toString();
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
package com.auxiliary.tool.date;
|
||||
|
||||
import java.time.temporal.ChronoUnit;
|
||||
|
||||
/**
|
||||
* <p><b>文件名:</b>TimeUnit.java</p>
|
||||
* <p><b>用途:</b>
|
||||
* 指定允许使用的时间单位
|
||||
* </p>
|
||||
* <p><b>编码时间:</b>2021年1月20日上午7:54:09</p>
|
||||
* <p><b>修改时间:</b>2021年1月20日上午7:54:09</p>
|
||||
* @author
|
||||
* @version Ver1.0
|
||||
* @since JDK 1.8
|
||||
*
|
||||
*/
|
||||
public enum TimeUnit {
|
||||
/**
|
||||
* 指向计算单位“<b>年</b>”,对应的时间单位为:年、y、Y
|
||||
*/
|
||||
YEAR("[年yY]", ChronoUnit.YEARS, (long)(365.25 * 1000L * 24L * 60L * 60L)),
|
||||
/**
|
||||
* 指向计算单位“<b>月</b>”,对应的时间单位为:月、m、M
|
||||
*/
|
||||
MONTH("[月mM]", ChronoUnit.MONTHS, (long)(30.4375 * 1000L * 24L * 60L * 60L)),
|
||||
/**
|
||||
* 指向计算单位“<b>周</b>”,对应的时间单位为:周、w、W
|
||||
*/
|
||||
WEEK("[周wW]", ChronoUnit.WEEKS, (7L * 24L * 60L * 60L * 1000L)),
|
||||
/**
|
||||
* 指向计算单位“<b>日</b>”,对应的时间单位为:日、d、D
|
||||
*/
|
||||
DAY("[日dD]", ChronoUnit.DAYS, (24L * 60L * 60L * 1000L)),
|
||||
/**
|
||||
* 指向计算单位“<b>时</b>”,对应的时间单位为:时、h、H
|
||||
*/
|
||||
HOUR("[时hH]", ChronoUnit.HOURS, (60L * 60L * 1000L)),
|
||||
/**
|
||||
* 指向计算单位“<b>分</b>”,对应的时间单位为:分、min(所有字母不区分大小写)
|
||||
*/
|
||||
MINUTE("分|((m|M)(i|I)(n|N))", ChronoUnit.MINUTES, (60L * 1000L)),
|
||||
/**
|
||||
* 指向计算单位“<b>秒</b>”,对应的时间单位为:秒、s、S
|
||||
*/
|
||||
SECOND("[秒sS]", ChronoUnit.SECONDS, (1000L)),
|
||||
;
|
||||
/**
|
||||
* 指定判断当前单位的正则
|
||||
*/
|
||||
private String unitRegex;
|
||||
/**
|
||||
* 存储转换为毫秒值所需的乘积
|
||||
*/
|
||||
private long toMillisNum;
|
||||
/**
|
||||
* 指向当前的单位在{@link ChronoUnit}中的映射
|
||||
*/
|
||||
private ChronoUnit chronoUnit;
|
||||
|
||||
/**
|
||||
* 初始化枚举值
|
||||
* @param unitRegex 单位判断正则
|
||||
* @param chronoUnit {@link ChronoUnit}的映射
|
||||
* @param toMillisNum 转换为毫秒值所需的乘积
|
||||
*/
|
||||
private TimeUnit(String unitRegex, ChronoUnit chronoUnit, long toMillisNum) {
|
||||
this.unitRegex = unitRegex;
|
||||
this.toMillisNum = toMillisNum;
|
||||
this.chronoUnit = chronoUnit;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于返回单位转换为毫秒值所需的乘积
|
||||
* <p>
|
||||
* <b>注意:</b>在返回年、月单位的毫秒值乘积时,由于无法精确知道具体经过的闰年数与31天的月份数,故
|
||||
* 年、月的毫秒值乘积返回取的是平均值,在精确计算时会存在误差
|
||||
* </p>
|
||||
* @return 单位转换为毫秒值所需的乘积
|
||||
*/
|
||||
public long getToMillisNum() {
|
||||
return toMillisNum;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于返回单位在{@link ChronoUnit}的映射
|
||||
* @return {@link ChronoUnit}的映射
|
||||
*/
|
||||
public ChronoUnit getChronoUnit() {
|
||||
return chronoUnit;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于判断传入的单位是否符合当前枚举值
|
||||
* @param unit 单位
|
||||
* @return 是否符合当前枚举
|
||||
*/
|
||||
public boolean isTimeUnit(String unit) {
|
||||
return unit.matches(unitRegex);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,205 @@
|
|||
package com.auxiliary.tool.date;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* <b>文件名:</b>TimeUtil.java
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>用途:</b> 提供对{@link Time}类进行扩展的方法
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>编码时间:</b>2021年1月22日下午7:52:10
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>修改时间:</b>2021年1月22日下午7:52:10
|
||||
* </p>
|
||||
*
|
||||
* @author 彭宇琦
|
||||
* @version Ver1.0
|
||||
* @since JDK 1.8
|
||||
*
|
||||
*/
|
||||
public class TimeUtil {
|
||||
private TimeUtil() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于随机生成一个起始时间与结束时间范围内的一个时间
|
||||
* <p>
|
||||
* 方法可通过传入的单位来限制随机产生的时间最小的变动单位,例如: <code><pre>
|
||||
* Time startTime = Time.parse("2020-12-20 00:00:00");
|
||||
* Time endTime = Time.parse("2020-12-22 00:00:00");
|
||||
*
|
||||
* TimeUtil.randomTime(startTime, endTime, TimeUnit.SECONDS)
|
||||
* TimeUtil.randomTime(startTime, endTime, TimeUnit.DAYS)
|
||||
* </pre></code> 则在以上代码中,第一次调用方法可能得到一个“2020-12-21 17:31:22”的时间或其他的可能,但第二次调用方法
|
||||
* 仅得到“2020-12-20 00:00:00”或“2020-12-21 00:00:00”两种结果
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>注意:</b>
|
||||
* <ol>
|
||||
* <li>在生成随机时间的范围中,允许生成起始时间,但不会生成结束时间</li>
|
||||
* <li>在随机时间中,不变的时间与起始时间一致。例如,最小的变动单位为“日”,则在生成的时间中,其时间的 时、分、秒的数值都与起始时间保持一致</li>
|
||||
* <li>若起始时间大于结束时间,则会自动对时间进行调换;若起始时间与结束时间一致,则直接返回起始时间</li>
|
||||
* </ol>
|
||||
* </p>
|
||||
*
|
||||
* @param startTime 随机时间的起始时间
|
||||
* @param endTime 随机时间的结束时间
|
||||
* @param timeUnit 随机时间最小变动单位
|
||||
* @return 随机的时间
|
||||
*/
|
||||
public static Time randomTime(Time startTime, Time endTime, TimeUnit timeUnit) {
|
||||
// 判断传入的对象是否为空
|
||||
if (startTime == null || endTime == null || timeUnit == null) {
|
||||
throw new IncorrectConditionException(String
|
||||
.format("必须指定时间范围与最小变动单位:[startTime:%s, endTime:%s, timeUnit:%s]", startTime, endTime, timeUnit));
|
||||
}
|
||||
|
||||
//若开始时间大于结束时间,则交换两个时间;若一致,则直接返回起始时间
|
||||
int compareResult = startTime.compareTo(endTime);
|
||||
if (compareResult > 0) {
|
||||
Time tempTime = startTime;
|
||||
startTime = endTime;
|
||||
endTime = tempTime;
|
||||
} else if (compareResult == 0) {
|
||||
return startTime;
|
||||
} else {
|
||||
}
|
||||
|
||||
// 获取开始时间与结束时间的毫秒值,之后通过指定的单位对毫秒值进行转换
|
||||
long startTime2Unit = startTime.getMilliSecond() / timeUnit.getToMillisNum();
|
||||
//若结束时间与起始时间相同,则在结束时间的毫秒值上加上1
|
||||
long endTime2Unit = endTime.getMilliSecond() / timeUnit.getToMillisNum();
|
||||
|
||||
//判断当前转换单位后,得到的结果是否一致,若结果一致,则仍无需计算随机时间
|
||||
Time randomTime;
|
||||
if (startTime2Unit != endTime2Unit) {
|
||||
// 生成随机的经转换的数值,并乘以单位乘积,转换成毫秒值后,再将毫秒值转换为时间
|
||||
randomTime = Time.parse((new Random().longs(startTime2Unit, endTime2Unit).findAny().orElse(startTime2Unit))
|
||||
* timeUnit.getToMillisNum());
|
||||
|
||||
// 为保证精度,则根据最小变动的单位,将起始时间的下级单位的数值赋给生成的时间
|
||||
LocalDateTime startTimeLocal = startTime.getLocalDateTime();
|
||||
switch (timeUnit) {
|
||||
case YEAR:
|
||||
randomTime.setTime(startTimeLocal.getMonthValue(), TimeUnit.MONTH);
|
||||
case MONTH:
|
||||
// 若当前月份无开始时间指向的日期(一般为本月最后一天),则将日期改为当月的最后一天
|
||||
try {
|
||||
randomTime.setTime(startTimeLocal.getDayOfMonth(), TimeUnit.DAY);
|
||||
} catch (IncorrectConditionException e) {
|
||||
randomTime = Time.parse(InitTimeUtil.lastDayOfMonth(false, randomTime.getLocalDateTime()));
|
||||
}
|
||||
case WEEK:
|
||||
case DAY:
|
||||
randomTime.setTime(startTimeLocal.getHour(), TimeUnit.HOUR);
|
||||
case HOUR:
|
||||
randomTime.setTime(startTimeLocal.getMinute(), TimeUnit.MINUTE);
|
||||
case MINUTE:
|
||||
randomTime.setTime(startTimeLocal.getSecond(), TimeUnit.SECOND);
|
||||
case SECOND:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
randomTime = startTime;
|
||||
}
|
||||
|
||||
// 根据毫秒值转换为Time对象
|
||||
return randomTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于以当前时间和指定的时间为随机时间范围,生成一个随机的时间
|
||||
* <p>
|
||||
* 若当前时间大于指定的时间,则将当前时间作为结束时间进行处理;
|
||||
* 若当前时间小于指定的时间,则将当前时间作为起始时间进行处理。
|
||||
* 详细参数说明可参考{@link #randomTime(Time, Time, TimeUnit)}
|
||||
* </p>
|
||||
* @param time 指定的时间
|
||||
* @param timeUnit 随机时间最小变动单位
|
||||
* @return 随机的时间
|
||||
*/
|
||||
public static Time randomTime(Time time, TimeUnit timeUnit) {
|
||||
return randomTime(Time.parse(), time, timeUnit);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于计算指定时间与待比较时间之间差值,并以{@link Duration}的形式对计算结果进行返回
|
||||
* @param time 指定时间
|
||||
* @param compareTime 待比较时间
|
||||
* @return 两时间的差值
|
||||
*/
|
||||
public static Duration timeDifference(Time time, Time compareTime) {
|
||||
// 判断传入的对象是否为空
|
||||
if (time == null || compareTime == null) {
|
||||
throw new IncorrectConditionException(String
|
||||
.format("必须指定时间范围与最小变动单位:[time:%s, compareTime:%s]", time, compareTime));
|
||||
}
|
||||
|
||||
return Duration.between(time.getLocalDateTime(), compareTime.getLocalDateTime());
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于计算指定时间与待比较时间之间各个单位的差值,并以{@link Map}的形式进行返回
|
||||
* <p>
|
||||
* 在返回值中,其键为时间单位,值为该单位的差值
|
||||
* </p>
|
||||
* @param time 指定时间
|
||||
* @param compareTime 待比较时间
|
||||
* @return 两时间的差值
|
||||
*/
|
||||
/* TODO 暂时搁置 未想到解决借位或精度的解决办法
|
||||
public static Map<TimeUnit, Integer> timeDifferenceToMap(Time time, Time compareTime) {
|
||||
// 判断传入的对象是否为空
|
||||
if (time == null || compareTime == null) {
|
||||
throw new IncorrectConditionException(String
|
||||
.format("必须指定时间范围与最小变动单位:[time:%s, compareTime:%s]", time, compareTime));
|
||||
}
|
||||
|
||||
//存储转换单位后的数据
|
||||
Map<TimeUnit, Integer> UnitMap = new HashMap<>();
|
||||
TimeUnit unit = TimeUnit.YEAR;
|
||||
//循环,直到毫秒值小于1000时(单位已计算至毫秒)结束
|
||||
while(unit != null) {
|
||||
int value = 0;
|
||||
switch (unit) {
|
||||
case YEAR:
|
||||
value = time.getLocalDateTime().getYear() - compareTime.getLocalDateTime().getYear();
|
||||
unit = TimeUnit.MONTH;
|
||||
break;
|
||||
case MONTH:
|
||||
value = time.getLocalDateTime().getMonthValue() - compareTime.getLocalDateTime().getMonthValue();
|
||||
if (value < 0) {
|
||||
UnitMap.put(TimeUnit.YEAR, UnitMap.get(TimeUnit.YEAR) - 1);
|
||||
value = 12 + value;
|
||||
}
|
||||
unit = TimeUnit.DAY;
|
||||
break;
|
||||
case DAY:
|
||||
unit = TimeUnit.HOUR;
|
||||
break;
|
||||
case HOUR:
|
||||
unit = TimeUnit.MINUTE;
|
||||
break;
|
||||
case MINUTE:
|
||||
unit = TimeUnit.SECOND;
|
||||
break;
|
||||
case SECOND:
|
||||
default:
|
||||
unit = null;
|
||||
break;
|
||||
}
|
||||
|
||||
UnitMap.put(unit, value);
|
||||
}
|
||||
|
||||
return UnitMap;
|
||||
}
|
||||
*/
|
||||
}
|
|
@ -307,7 +307,7 @@ public class TableFileReadUtil {
|
|||
// 判断单元格内的数据是否为日期
|
||||
if (DateUtil.isCellDateFormatted(cell)) {
|
||||
// 将单元格内容转换为Date后,在time中进行存储
|
||||
Time time = new Time(cell.getDateCellValue());
|
||||
Time time = Time.parse(cell.getDateCellValue());
|
||||
// 根据存储的时间格式,对时间进行转换,输出格式化后的时间
|
||||
return time.getFormatTime();
|
||||
} else {
|
||||
|
|
Loading…
Reference in New Issue