Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DateTime parsing error when the system has customized datetime format #76

Open
strawhatboy opened this issue Oct 25, 2024 · 2 comments
Open

Comments

@strawhatboy
Copy link

strawhatboy commented Oct 25, 2024

Env

Win11pro 23H2
dotnet8

How to reproduce

  1. Change system date time format: Control Panel-> Region-> Additional Settings-> "Date" tab-> Short date.
  2. Change the "Short date" from "M/d/yyyy" to "M/d/yyyy/dddd" which will append the dayofweek, like "10/25/2024/Friday"
  3. Try to extract something by calling ArchiveFile.Extract

Expected

Extracted successfully.

Actual

System.FormatException was thrown

System.FormatException: String '' was not recognized as a valid DateTime.
   at System.DateTimeParse.Parse(ReadOnlySpan`1 s, DateTimeFormatInfo dtfi, DateTimeStyles styles)
   at System.Convert.ToDateTime(String value, IFormatProvider provider)
   at System.Convert.ChangeType(Object value, Type conversionType, IFormatProvider provider)
   at SevenZipExtractor.ArchiveFile.GetProperty[T](UInt32 fileIndex, ItemPropId name) in C:\Users\Andy\lab\ztmz_pacenote\src\SevenZipExtractor\SevenZipExtractor\ArchiveFile.cs:line 249
   at SevenZipExtractor.ArchiveFile.GetPropertySafe[T](UInt32 fileIndex, ItemPropId name) in C:\Users\Andy\lab\ztmz_pacenote\src\SevenZipExtractor\SevenZipExtractor\ArchiveFile.cs:line 213
   at SevenZipExtractor.ArchiveFile.get_Entries() in C:\Users\Andy\lab\ztmz_pacenote\src\SevenZipExtractor\SevenZipExtractor\ArchiveFile.cs:line 174
   at SevenZipExtractor.ArchiveFile.Extract(Func`2 getOutputPath) in C:\Users\Andy\lab\ztmz_pacenote\src\SevenZipExtractor\SevenZipExtractor\ArchiveFile.cs:line 104
   at SevenZipExtractor.ArchiveFile.Extract(String outputFolder, Boolean overwrite) in C:\Users\Andy\lab\ztmz_pacenote\src\SevenZipExtractor\SevenZipExtractor\ArchiveFile.cs:line 80

because in T result = (T)Convert.ChangeType(value.ToString(), underlyingType);, value.ToString() will output "10/25/2024/Friday 18:00:00", while this format cannot be parsed to DateTime by default. thus in method private T GetPropertySafe<T>(uint fileIndex, ItemPropId name), only InvalidCastException was handled, but FormatException was not. it's not safe now XD.

@435201823
Copy link

I also encountered the same error, and I found that this error originates from Convert, ultimately tracing back to the dotnet runtime. My temporary solution is as follows:

public static void setCurrentCulture()
{
    // 获取当前的文化信息
    CultureInfo currentCulture = (CultureInfo)CultureInfo.CurrentCulture.Clone();

    // 修改格式
    currentCulture.DateTimeFormat.ShortDatePattern = "yyyy/M/d";
    currentCulture.DateTimeFormat.LongDatePattern = "yyyy'年'M'月'd'日'";
    currentCulture.DateTimeFormat.ShortTimePattern = "H:mm";
    currentCulture.DateTimeFormat.LongTimePattern = "H:mm:ss";
    currentCulture.DateTimeFormat.FirstDayOfWeek = DayOfWeek.Monday;

    // 设置当前线程的文化信息
    CultureInfo.CurrentCulture = currentCulture;
}

@strawhatboy
Copy link
Author

I also encountered the same error, and I found that this error originates from Convert, ultimately tracing back to the dotnet runtime. My temporary solution is as follows:

public static void setCurrentCulture()
{
    // 获取当前的文化信息
    CultureInfo currentCulture = (CultureInfo)CultureInfo.CurrentCulture.Clone();

    // 修改格式
    currentCulture.DateTimeFormat.ShortDatePattern = "yyyy/M/d";
    currentCulture.DateTimeFormat.LongDatePattern = "yyyy'年'M'月'd'日'";
    currentCulture.DateTimeFormat.ShortTimePattern = "H:mm";
    currentCulture.DateTimeFormat.LongTimePattern = "H:mm:ss";
    currentCulture.DateTimeFormat.FirstDayOfWeek = DayOfWeek.Monday;

    // 设置当前线程的文化信息
    CultureInfo.CurrentCulture = currentCulture;
}

That's brilliant!
I solved it by the HarmonyLib method patching trick 😂 to catch any exception instead of InvalidCastException only:

public static class ArchiveFilePatch
{
    private static Type PropNameId = AccessTools.TypeByName("SevenZipExtractor.ItemPropId");
    public static void Patch(Harmony harmony)
    {
        var original = AccessTools.Method(typeof(SevenZipExtractor.ArchiveFile), "GetPropertySafe", new Type[] { typeof(uint), PropNameId }).MakeGenericMethod(typeof(DateTime));
        var prefix = AccessTools.Method(typeof(ArchiveFilePatch), "GetPropertySafe");
        harmony.Patch(original, new HarmonyMethod(prefix));
    }
    public static bool GetPropertySafe(uint fileIndex, object name, ref DateTime __result, ref ArchiveFile __instance)
    {
        try
        {
            MethodInfo method = __instance.GetType().GetMethod("GetProperty", AccessTools.all).MakeGenericMethod(typeof(DateTime));
            if (method == null)
            {
                __result = default(DateTime);
                return false;
            } else {
                __result = (DateTime)method.Invoke(__instance, new object[] { fileIndex, name });
                return false;
            }
        }
        catch (Exception)
        {
            __result = default(DateTime);
        }
        return false;
    }
}

and call the Patch method at the entry point:

HarmonyLib.Harmony harmony = new HarmonyLib.Harmony("xxxx");
// patch to fix the SevenZipExtractor issue
ArchiveFilePatch.Patch(harmony);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants