19 Commits
Author SHA1 Message Date
timi ee6e549e17 Merge pull request 'v0.1.1' (#15) from dev into master
Reviewed-on: #15
2026-10-08 00:38:55 +00:00
Timi 53d9a5b18e v0.1.1
CI/CD / build-deploy (pull_request) Successful in 11s
2026-10-08 08:38:34 +08:00
timi 43f75bc64d Merge pull request 'v0.1.0' (#14) from dev into master
Reviewed-on: #14
2026-09-30 03:49:10 +00:00
Timi 0dd2e1627f v0.1.0
CI/CD / build-deploy (pull_request) Successful in 10s
2026-09-30 11:48:54 +08:00
timi 8dcd803033 Merge pull request 'v0.0.14' (#13) from dev into master
Reviewed-on: #13
2026-09-29 11:56:01 +00:00
Timi f2ac37b035 v0.0.14
CI/CD / build-deploy (pull_request) Successful in 14s
2026-09-29 19:55:44 +08:00
timi 11f7f50603 Merge pull request 'v0.0.13' (#12) from dev into master
Reviewed-on: #12
2026-08-11 15:58:32 +00:00
Timi 3fb1363d8e v0.0.13
CI/CD / build-deploy (pull_request) Successful in 11s
2026-08-11 23:55:18 +08:00
timi f354c232fe Merge pull request 'v0.0.12' (#11) from dev into master
Reviewed-on: #11
2026-07-31 07:13:16 +00:00
Timi 66fc228d1f v0.0.12
CI/CD / build-deploy (pull_request) Successful in 14s
2026-07-31 15:12:33 +08:00
Timi 92e60b9c5b update password char pool 2026-07-21 14:34:51 +08:00
timi c75b1b895c Merge pull request 'v0.0.11' (#10) from dev into master
Reviewed-on: #10
2026-06-30 08:13:48 +00:00
Timi 810b184e53 v0.0.11
CI/CD / build-deploy (pull_request) Successful in 10s
2026-06-30 16:13:15 +08:00
timi 06abba8765 Merge pull request 'v0.0.10' (#9) from dev into master
Reviewed-on: #9
2026-06-30 07:38:00 +00:00
Timi 21480a37a2 v0.0.10
CI/CD / build-deploy (pull_request) Successful in 10s
2026-06-30 15:35:43 +08:00
timi 4e8351fee9 Merge pull request 'v0.0.9' (#8) from dev into master
Reviewed-on: #8
2026-06-30 07:23:51 +00:00
Timi 1017129c1a v0.0.9
CI/CD / build-deploy (pull_request) Successful in 9s
2026-06-30 15:23:19 +08:00
Timi 50d9296952 add Text.randomPassword 2026-06-11 12:08:09 +08:00
Timi 4162b75de9 fix random text pool 2026-06-08 19:17:45 +08:00
8 changed files with 97 additions and 82 deletions
+4 -4
View File
@@ -6,7 +6,7 @@
<groupId>com.imyeyu.utils</groupId>
<artifactId>timi-utils</artifactId>
<version>0.0.8</version>
<version>0.1.1</version>
<properties>
<maven.test.skip>true</maven.test.skip>
@@ -49,7 +49,7 @@
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.36</version>
<version>1.18.46</version>
</dependency>
</dependencies>
</plugin>
@@ -91,7 +91,7 @@
<dependency>
<groupId>com.imyeyu.java</groupId>
<artifactId>timi-java</artifactId>
<version>0.0.4</version>
<version>0.2.0</version>
</dependency>
<dependency>
<groupId>de.mkammerer</groupId>
@@ -108,7 +108,7 @@
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.34</version>
<version>1.18.46</version>
</dependency>
</dependencies>
</project>
@@ -1,8 +1,8 @@
package com.imyeyu.utils;
import com.imyeyu.java.bean.CallbackArgReturn;
import com.imyeyu.java.bean.timi.TimiCode;
import com.imyeyu.java.bean.timi.TimiException;
import com.imyeyu.java.bean.ResultCode;
import com.imyeyu.java.bean.ActionException;
import com.imyeyu.java.ref.Ref;
import java.util.ArrayList;
@@ -156,7 +156,7 @@ public class AsciiTable<T> {
}
return sb.toString();
} catch (IllegalAccessException e) {
throw new TimiException(TimiCode.ERROR, e.getMessage(), e);
throw new ActionException(ResultCode.ERROR, e.getMessage(), e);
}
}
@@ -165,7 +165,7 @@ public class AsciiTable<T> {
}
public void addHeader(String name, String field) {
TimiException.required(field, "not found field");
ActionException.required(field, "not found field");
ColMapping<T> colMapping = new ColMapping<>();
colMapping.name = name;
+3 -3
View File
@@ -1,7 +1,7 @@
package com.imyeyu.utils;
import com.imyeyu.java.bean.timi.TimiCode;
import com.imyeyu.java.bean.timi.TimiException;
import com.imyeyu.java.bean.ActionException;
import com.imyeyu.java.bean.ResultCode;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
@@ -39,7 +39,7 @@ public class Decoder {
unicode.setLength(0);
inUnicode = false;
} catch (NumberFormatException nfe) {
throw new TimiException(TimiCode.ERROR, "Unable to parse unicode value: " + unicode);
throw new ActionException(ResultCode.ERROR, "Unable to parse unicode value: " + unicode);
}
}
continue;
+3 -3
View File
@@ -1,8 +1,8 @@
package com.imyeyu.utils;
import com.imyeyu.java.TimiJava;
import com.imyeyu.java.bean.timi.TimiCode;
import com.imyeyu.java.bean.timi.TimiException;
import com.imyeyu.java.bean.ActionException;
import com.imyeyu.java.bean.ResultCode;
import java.io.StringWriter;
import java.net.IDN;
@@ -156,7 +156,7 @@ public class Encoder {
URI uri = new URI(url.getProtocol(), url.getUserInfo(), IDN.toASCII(url.getHost()), url.getPort(), url.getPath(), url.getQuery(), url.getRef());
return uri.toASCIIString().replace("+", "%2B");
} catch (MalformedURLException | URISyntaxException e) {
throw new TimiException(TimiCode.ERROR, e.getMessage());
throw new ActionException(ResultCode.ERROR, e.getMessage());
}
}
+2 -2
View File
@@ -52,8 +52,8 @@ public class Regex {
/** 用户名 (4-16 位字母、数字、下划线) */
public static final String USERNAME = "^[a-zA-Z0-9_]{4,16}$";
/** 密码 (6-18 位,包含字母和数字) */
public static final String PASSWORD = "^(?=.*[a-zA-Z])(?=.*\\d)[a-zA-Z0-9]{6,18}$";
/** 密码 (6-18 位,包含字母和数字,允许特殊字符) */
public static final String PASSWORD = "^(?=.*[a-zA-Z])(?=.*\\d)[a-zA-Z0-9!#$%&()*+,\\-./:;<=>?@\\[\\]\\^_`{|}~]{6,32}$";
/** 中文字符 */
public static final String CHINESE_CHAR = "^[\\u4e00-\\u9fa5]+$";
+27 -3
View File
@@ -19,9 +19,9 @@ public class Text {
public static String NUMBER_POOL = "0123456789";
public static String LETTER_NUMBER_POOL = LETTER_POOL + LETTER_POOL;
public static String LETTER_NUMBER_POOL = LETTER_POOL + NUMBER_POOL;
public static String PASSWORD_CHAR_POOL = LETTER_NUMBER_POOL + "!#$%&()*+,-./:;<=>?@[]^_`{|}~";
public static String PASSWORD_CHAR_POOL = LETTER_NUMBER_POOL + "!@#$%^&*-_=+[]{}|;:./?";
/** 十六进制小写 */
public static char[] HEX_DIGITS_LOWER = (NUMBER_POOL + "abcdef").toCharArray();
@@ -165,11 +165,31 @@ public class Text {
SecureRandom r = new SecureRandom();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < length; i++) {
sb.append(pool.charAt(r.nextInt(pool.length() - 1)));
sb.append(pool.charAt(r.nextInt(pool.length())));
}
return sb.toString();
}
public static String randomPassword(int length) {
if (length < 6 || 32 < length) {
throw new IllegalArgumentException("Password length must be between 6 and 32");
}
SecureRandom r = new SecureRandom();
char[] chars = new char[length];
chars[0] = LETTER_POOL.charAt(r.nextInt(LETTER_POOL.length()));
chars[1] = NUMBER_POOL.charAt(r.nextInt(NUMBER_POOL.length()));
for (int i = 2; i < length; i++) {
chars[i] = PASSWORD_CHAR_POOL.charAt(r.nextInt(PASSWORD_CHAR_POOL.length()));
}
for (int i = chars.length - 1; 0 < i; i--) {
int j = r.nextInt(i + 1);
char temp = chars[i];
chars[i] = chars[j];
chars[j] = temp;
}
return new String(chars);
}
/**
* 较短的临时 UUID,如果使用在庞大的数据里,很可能会发生重复
*
@@ -415,4 +435,8 @@ public class Text {
public static String bizClassName(Class<?> clazz) {
return underscoreClassName(clazz).toUpperCase();
}
public static String normalize(String text) {
return TimiJava.defaultIfEmpty(text, null);
}
}
+18 -63
View File
@@ -1,14 +1,12 @@
package com.imyeyu.utils;
import com.imyeyu.java.TimiJava;
import lombok.Getter;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -77,6 +75,9 @@ public class Time {
/** 格式化 yyyy-MM-dd'T'HH:mm:ss */
public static final SimpleDateFormat dateTimeT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
/** 格式化 yyyy-MM-dd HH:mm:ss */
public static final SimpleDateFormat serialize = new SimpleDateFormat("yyyyMMddHHmmss");
// ---------- 长整型时间戳 ----------
/** 1 秒时间戳 */
@@ -105,31 +106,6 @@ public class Time {
/** 1 天时间戳(整型) */
public static final int DI = HI * 24;
/**
* 计算两个时间戳精确的日期时间差
*
* @param begin 开始时间戳
* @param end 结束时间戳
* @return 时差
*/
public static Between between(long begin, long end) {
if (end < begin) {
throw new IllegalArgumentException("end time must greater than begin time:" + end + " < " + begin);
}
LocalDateTime ldtBegin = toLocalDateTime(begin);
LocalDateTime ldtEnd = toLocalDateTime(end);
Between between = new Between();
between.year = (int) ChronoUnit.YEARS.between(ldtBegin, ldtEnd);
between.month = (int) ChronoUnit.MONTHS.between(ldtBegin, ldtEnd) % 12;
between.day = (int) ChronoUnit.DAYS.between(ldtBegin.plusMonths(between.year * 12L + between.month), ldtEnd);
between.hour = (int) (ChronoUnit.HOURS.between(ldtBegin, ldtEnd) - ChronoUnit.DAYS.between(ldtBegin, ldtEnd) * 24);
between.minute = (int) ChronoUnit.MINUTES.between(ldtBegin, ldtEnd) % 60;
between.second = (int) ChronoUnit.SECONDS.between(ldtBegin, ldtEnd) % 60;
between.millis = (int) ((end - begin) % 1000);
return between;
}
/**
* 获取此刻毫秒
*
@@ -154,7 +130,11 @@ public class Time {
* @return 昨天零时时间戳
*/
public static long yesterday() {
return today() - D;
return yesterday(now());
}
public static long yesterday(long time) {
return today(time) - D;
}
/**
@@ -163,9 +143,11 @@ public class Time {
* @return 今天零时时间戳
*/
public static long today() {
long now = now();
final long H8 = H * 8;
return ((now + H8 - (now + H8) % (H * 24)) - H8);
return today(now());
}
public static long today(long time) {
return Instant.ofEpochMilli(time).atZone(ZoneId.systemDefault()).toLocalDate().atStartOfDay(ZoneId.systemDefault()).toInstant().toEpochMilli();
}
/**
@@ -174,7 +156,11 @@ public class Time {
* @return 明天零时时间戳
*/
public static long tomorrow() {
return today() + D;
return tomorrow(now());
}
public static long tomorrow(long time) {
return today(time) + D;
}
/**
@@ -380,35 +366,4 @@ public class Time {
return String.format("%d:%02d:%02d.%03d", h, s / 60 - h * 60, s % 60, millis % 1000);
}
}
/**
* 时差
*
* @author 夜雨
* @version 2022-10-12 14:46
*/
@Getter
public static class Between {
/** 年 */
int year;
/** 月 */
int month;
/** 天 */
int day;
/** 小时 */
int hour;
/** 分钟 */
int minute;
/** 秒 */
int second;
/** 毫秒 */
int millis;
}
}
+36
View File
@@ -0,0 +1,36 @@
package test;
import com.imyeyu.utils.Regex;
import com.imyeyu.utils.Text;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertThrows;
/**
* @author 夜雨
* @since 2026-06-11 14:00
*/
public class TestRegex {
@Test
public void testPassword() {
assert Regex.isMatch(Regex.PASSWORD, "abc123");
assert Regex.isMatch(Regex.PASSWORD, "abc123!");
assert Regex.isMatch(Regex.PASSWORD, "Abc123[]^_`{|}~");
assert Regex.isMatch(Regex.PASSWORD, "A1!#$%&*+,-./:@?");
for (int i = 0; i < 20; i++) {
assert Regex.isMatch(Regex.PASSWORD, Text.randomPassword(20));
}
assert Regex.isNotMatch(Regex.PASSWORD, "abcdef!");
assert Regex.isNotMatch(Regex.PASSWORD, "123456!");
assert Regex.isNotMatch(Regex.PASSWORD, "Ab1!");
assert Regex.isNotMatch(Regex.PASSWORD, "Abcdefghijklmnopqrstuvwxzy123456!");
assert Regex.isNotMatch(Regex.PASSWORD, "Abc123\\");
assert Regex.isNotMatch(Regex.PASSWORD, "Abc123\"");
assert Regex.isNotMatch(Regex.PASSWORD, "Abc123'");
assert Regex.isNotMatch(Regex.PASSWORD, "Abc123 ");
assertThrows(IllegalArgumentException.class, () -> Text.randomPassword(5));
assertThrows(IllegalArgumentException.class, () -> Text.randomPassword(33));
}
}