Unity 之 切换语言导致报错:System.FormatException:String was not recognized as a valid DateTime.
Posted 陈言必行
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity 之 切换语言导致报错:System.FormatException:String was not recognized as a valid DateTime.相关的知识,希望对你有一定的参考价值。
Unity 之 切换语言导致报错:System.FormatException:String was not recognized as a valid DateTime.
一,发生问题
1.1 问题背景
最近在开发多语言本地化时(简体-繁体来回切换),发生了这个错误:System.FormatException: String was not recognized as a valid DateTime.
--> 系统格式异常:字符串未被识别为有效的日期时间。
看起来是逻辑上错误传了一个错误的字符串给DateTime.Parse(“”)
方法作为参数了。那么奇怪的是在编辑器下没有发生错误,在真机不切换语言的情况也没有发生错误,只有在IOS切换简繁体系统语言时会发生这个错误。
于是猜测在不同语言环境下DateTime.Now.ToString()
得到的结果是不同的,所以就有了2.1的测试用例。
1.2 报错日志
真机切换语言捕获的错误日志:
System.AggregateException: One or more errors occurred. ---> System.FormatException: String was not recognized as a valid DateTime.
at System.DateTimeParse.Parse (System.String s, System.Globalization.DateTimeFormatInfo dtfi, System.Globalization.DateTimeStyles styles) [0x00000] in <00000000000000000000000000000000>:0
at WZC.ActivityManager+<>c__DisplayClass45_0.<GetActivitySwitchConfig>b__0 (WZC.ActivitySwitchConfig e) [0x00000] in <00000000000000000000000000000000>:0
at System.Threading.ContextCallback.Invoke (System.Object state) [0x00000] in <00000000000000000000000000000000>:0
at System.Threading.ExecutionContext.RunInternal (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx) [0x00000] in <00000000000000000000000000000000>:0
at System.Runtime.CompilerServices.AsyncMethodBuilderCore+MoveNextRunner.Run () [0x00000] in <00000000000000000000000000000000>:0
at System.Action.Invoke () [0x00000] in <00000000000000000000000000000000>:0
at System.Threading.ContextCallback.Invoke (System.Object state) [0x00000] in <00000000000000000000000000000000>:0
at System.Threading.Tasks.AwaitTaskContinuation.RunCallback (System.Threading.ContextCallback callback, System.Object state, System.Threading.Tasks.Task& currentTask) [0x00000] in <00000000000000000000000000000000>:0
at System.Threading.Tasks.Task`1[TResult].TrySetResult (TResult result) [0x00000] in <00000000000000000000000000000000>:0
at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1[TResult].Create () [0x00000] in <00000000000000000000000000000000>:0
at WZC.ApiHelper..cctor () [0x00000] in <00000000000000000000000000000000>:0
at System.Threading.ContextCallback.Invoke (System.Object state) [0x00000] in <00000000000000000000000000000000>:0
at System.Threading.ExecutionContext.RunInternal (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx) [0x00000] in <00000000000000000000000000000000>:0
at System.Runtime.CompilerServices.AsyncMethodBuilderCore+MoveNextRunner.Run () [0x00000] in <00000000000000000000000000000000>:0
at System.Action.Invoke () [0x00000] in <00000000000000000000000000000000>:0
at System.Threading.ContextCallback.Invoke (System.Object state) [0x00000] in <00000000000000000000000000000000>:0
--- End of inner exception stack trace ---
二,定位问题
2.1 测试用例
按照游戏逻辑还原了DateTime的使用情况,为了方便观察日志创建了Scroll View
组件,里面放一个很长的Text
,测试代码和场景搭建效果如下:
using System;
using UnityEngine;
using UnityEngine.UI;
public class ConverTimeError : MonoBehaviour
public Text context;
public Button cunShiJian;
public Button quShiJian;
void Start()
var strRus = PlayerPrefs.GetString("Hall:RegionGetDate");
var strRusDate = DateTime.Parse(strRus);
context.text += "转换结果:+++" + strRusDate.Year + "/" + strRusDate.Month+ "/" + strRusDate.Day + ";\\n";
cunShiJian.onClick.AddListener(()=>
context.text += "存时间 :---" + DateTime.Now + ";\\n";
PlayerPrefs.SetString("Hall:RegionGetDate", DateTime.Now.ToString());
context.text += "存储结果:---" + PlayerPrefs.GetString("Hall:RegionGetDate") + ";\\n";
);
quShiJian.onClick.AddListener(()=>
context.text += "取时间 :+++" + DateTime.Now + ";\\n";
var regionGetDateStr = PlayerPrefs.GetString("Hall:RegionGetDate");
context.text += "取到结果:+++" + regionGetDateStr + ";\\n";
var regionGetDate = DateTime.Parse(regionGetDateStr);
context.text += "取到转换结果:+++" + regionGetDate.Year + "/" + regionGetDate.Month+ "/" + regionGetDate.Day + ";\\n";
);
使用此测试用例在macOS和ios上都进行了切换语言的测试,结果都没有任何异常,发现DateTime.Now.ToString()
的结果都是:月/日/年 时:分:秒 这种格式。
2.2 找到问题
测试用例没发现问题,那不得不在原工程中补日志了,几经周折最后确定了有一个存时间的字符串格式为日/月/年 时:分:秒
于是在编辑器中模拟转换了年/月/日
,月/日/年
和日/月/年
三种格式的时间转换:
Debug.Log("年/月/日: " + DateTime.Parse("2022/7/25 13:11:00"));
Debug.Log("月/日/年: " + DateTime.Parse("7/25/2022 13:11:00"));
// 有问题的时间格式转换
Debug.Log("日/月/年: " + DateTime.Parse("25/7/2022 13:11:00"));
结果表明:日/月/年
这种格式的字符串确实不能使用DateTime.Parse()
方法进行转换。
那么新的问题就来了,在时间存储时使用的是:DateTime.Now.ToString()
,而在2.1的测试用例中我们有确认了DateTime.Now.ToString()
的结果都是:月/日/年 时:分:秒 这种格式。
同时又可以确定的是游戏中存储时间使用的都是DateTime.Now.ToString()
这种形式,这就很让人费解游戏逻辑中日/月/年
格式的字符串是怎么出来的呢?
三,解决问题
3.1 尝试解决
刚开始是使用了
DateTime.ParseExact(DateTime.Now.ToString(), "yyyy/dd/MM", System.Globalization.CultureInfo.InvariantCulture);
这个方法来进行格式转换,因为这是指定格式的转换,所以根据上面的测试结果也是不行的。
3.2 解决问题
将存储的代码固定格式为:
DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss")
好在工程里面只有几处DateTime.Now
的赋值,修改起来还是很方便的。最后也测试通过了。
遇到了这么奇怪的问题,记录一下,供遇到相似问题童鞋参考一下。
以上是关于Unity 之 切换语言导致报错:System.FormatException:String was not recognized as a valid DateTime.的主要内容,如果未能解决你的问题,请参考以下文章