Android SimpleDateFormat.format 给出错误的数字金额,例如随机分钟“0040”
Android SimpleDateFormat.format giving wrong digit amount, like Minute "0040" randomly
我有一个 android 的应用程序,它有一个自定义的日志格式,我在前面加上日期以便更好地搜索。
目前我正在使用 SimpleDateFormat 但结果不一致。
这种不一致的几个例子,它给了我:
2018/10/11 10:40:21.229 ____Verbose:
2018/0010/0011 0010:40:21.230 ____Verbose:
2018/10/11 10:40:21.232 ____Verbose:
...
2018/10/11 10:40:42.784 ____Verbose:
2018/10/11 010:040:042.786 ____Verbose:
2018/10/11 10:40:42.786 ____Verbose:
我使用的代码是:
private static final DateFormat LOGDATEFULL = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS");
private static String strErrorLevel(int errorLevel){
if (errorLevel == VERBOSE ) return " ____ VERBOSE: ";
if (errorLevel == DEBUG ) return " ____ DEBUG : ";
if (errorLevel == INFO ) return " _.._ INFO : ";
if (errorLevel == WARN ) return " _--_ WARN : ";
if (errorLevel == ERROR ) return " _!!_ ERROR : ";
if (errorLevel == ANALYTICS) return " _++_ ANALYTC: ";
return " _**_ ASSERT : ";
}
public static void customLog(String message, int level){
Date currDate = Calendar.getInstance().getTime();
Log.d(LOGDATEFULL.format(currDate) + " " + strErrorLevel(level) + message);
}
我的系统区域设置是巴西葡萄牙语 (pt-BR),从主线程调用和从其他线程调用时都会出现这种情况。
除了创建一个函数来手动制作字符串之外,还有其他解决方案吗?
顺便说一句,它甚至发生在为文件生成名称时,如 'Output_2018-010-11.txt.
答:确实是 and 指出的,所有我用SimpleDateFormat的地方,只有这个可以访问一次通过一个以上的线程。我选择 Tom G 答案是为了在现有代码中实现的实用性。
谢谢
如果您使用来自多线程的 SimpleDateFormat
实例,您可能会在那里遇到竞争条件,正如已经指出的那样,class 不是线程安全的。来自 official docs:
Date formats are not synchronized. It is recommended to create
separate format instances for each thread. If multiple threads access
a format concurrently, it must be synchronized externally.
您应该同步对该实例的访问:
public static void customLog(String message, int level){
Date currDate = Calendar.getInstance().getTime();
synchronized(LOGDATEFULL) {
Log.d(LOGDATEFULL.format(currDate) + " " + strErrorLevel(level) + message);
}
}
的替代方法是将格式化程序包装在 ThreadLocal
中,如下所示:
private static final ThreadLocal<DateFormat> LOGDATEFULL = new ThreadLocal<>() {
@Override protected DateFormat initialValue() {
return new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS");
}
}
然后您将通过调用 .get().format()
来访问它。
这使您可以避免协调对单个实例的访问的同步开销,而不必担心手动为单独的线程创建单独的副本。
我有一个 android 的应用程序,它有一个自定义的日志格式,我在前面加上日期以便更好地搜索。 目前我正在使用 SimpleDateFormat 但结果不一致。
这种不一致的几个例子,它给了我:
2018/10/11 10:40:21.229 ____Verbose:
2018/0010/0011 0010:40:21.230 ____Verbose:
2018/10/11 10:40:21.232 ____Verbose:
...
2018/10/11 10:40:42.784 ____Verbose:
2018/10/11 010:040:042.786 ____Verbose:
2018/10/11 10:40:42.786 ____Verbose:
我使用的代码是:
private static final DateFormat LOGDATEFULL = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS");
private static String strErrorLevel(int errorLevel){
if (errorLevel == VERBOSE ) return " ____ VERBOSE: ";
if (errorLevel == DEBUG ) return " ____ DEBUG : ";
if (errorLevel == INFO ) return " _.._ INFO : ";
if (errorLevel == WARN ) return " _--_ WARN : ";
if (errorLevel == ERROR ) return " _!!_ ERROR : ";
if (errorLevel == ANALYTICS) return " _++_ ANALYTC: ";
return " _**_ ASSERT : ";
}
public static void customLog(String message, int level){
Date currDate = Calendar.getInstance().getTime();
Log.d(LOGDATEFULL.format(currDate) + " " + strErrorLevel(level) + message);
}
我的系统区域设置是巴西葡萄牙语 (pt-BR),从主线程调用和从其他线程调用时都会出现这种情况。
除了创建一个函数来手动制作字符串之外,还有其他解决方案吗?
顺便说一句,它甚至发生在为文件生成名称时,如 'Output_2018-010-11.txt.
答:确实是
谢谢
如果您使用来自多线程的 SimpleDateFormat
实例,您可能会在那里遇到竞争条件,正如已经指出的那样,class 不是线程安全的。来自 official docs:
Date formats are not synchronized. It is recommended to create separate format instances for each thread. If multiple threads access a format concurrently, it must be synchronized externally.
您应该同步对该实例的访问:
public static void customLog(String message, int level){
Date currDate = Calendar.getInstance().getTime();
synchronized(LOGDATEFULL) {
Log.d(LOGDATEFULL.format(currDate) + " " + strErrorLevel(level) + message);
}
}
ThreadLocal
中,如下所示:
private static final ThreadLocal<DateFormat> LOGDATEFULL = new ThreadLocal<>() {
@Override protected DateFormat initialValue() {
return new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS");
}
}
然后您将通过调用 .get().format()
来访问它。
这使您可以避免协调对单个实例的访问的同步开销,而不必担心手动为单独的线程创建单独的副本。