From 7041cc7c1e70505c647b184412362a16f0a8d286 Mon Sep 17 00:00:00 2001 From: tombogle Date: Sat, 24 May 2025 17:25:00 -0400 Subject: [PATCH 1/2] Added support for date insertion in localized files --- CHANGELOG.md | 7 + SIL.BuildTasks.Tests/FileUpdateTests.cs | 199 ++++++++++++++++++++++++ SIL.BuildTasks/FileUpdate.cs | 105 +++++++++++-- 3 files changed, 302 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fc313936..d564379f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +### Added +- [SIL.BuildTasks] Added FileUpdate.FileLocalePattern (optional param) to infer a locale (e.g., for a localized release notes file) to use when doing date insertion involving month names or abbreviations. + +### Changed + +- [SIL.BuildTasks] Changed FileUpdate.DatePlaceholder to allow the caller to specify a special placeholder `_DATE(*)_` that will look not only for `_DATE_` but also variants that include a date format specifier, such as `_DATE(MMM d, yyyy)_` or `_DATE(MM/yyyy)_` and will use the date format specified instead of the DateFormat. + ## [3.1.1] - 2025-03-18 ### Changed diff --git a/SIL.BuildTasks.Tests/FileUpdateTests.cs b/SIL.BuildTasks.Tests/FileUpdateTests.cs index db9dfdb6..052ddad1 100644 --- a/SIL.BuildTasks.Tests/FileUpdateTests.cs +++ b/SIL.BuildTasks.Tests/FileUpdateTests.cs @@ -2,6 +2,7 @@ // This software is licensed under the MIT License (http://opensource.org/licenses/MIT) using System; +using System.Globalization; using NUnit.Framework; // Sadly, Resharper wants to change Is.EqualTo to NUnit.Framework.Is.EqualTo // ReSharper disable AccessToStaticMemberViaDerivedType @@ -62,6 +63,120 @@ public void GetModifiedContents_RegexTextNotMatched_Throws(string origContents, Assert.That(ex.Message, Is.EqualTo($"No replacements made. Regex: '{regex}'; ReplacementText: '{replacement}'")); } + [TestCase("_DATE_ _VERSION_\r\nStuff", "_DATE_", "M/yyyy", "{0} 3.2.1\r\nStuff")] + [TestCase("_DATE_ _VERSION_\r\nStuff done before _DATE_", "_DATE_", "M/yyyy", "{0} 3.2.1\r\nStuff done before {0}")] + [TestCase("&DATE; _VERSION_\r\n- point #1", "&DATE;", "dd-MM-yy", "{0} 3.2.1\r\n- point #1")] + [TestCase("DATE _VERSION_", "DATE", "dd MMMM, yyyy", "{0} 3.2.1")] + [TestCase("DATE _VERSION_", "DATE", null, "{0} 3.2.1")] + public void GetModifiedContents_DateLiteral_InsertsDateWithSpecifiedDateFormat( + string origContents, string datePlaceholder, string dateFormat, + string expectedResultFormat) + { + var updater = new FileUpdate + { + Regex = "_VERSION_", + ReplacementText = "3.2.1", + DatePlaceholder = datePlaceholder, + DateFormat = dateFormat + }; + + var currentDate = DateTime.UtcNow.Date.ToString(dateFormat ?? updater.DateFormat); + + var result = updater.GetModifiedContents(origContents); + var expectedResult = string.Format(expectedResultFormat, currentDate); + Assert.That(result, Is.EqualTo(expectedResult)); + } + + [TestCase("_DATE_ _VERSION_\r\nStuff", "M/yyyy", "{0} 3.2.1\r\nStuff")] + [TestCase("_DATE_ _VERSION_\r\nStuff done before _DATE_", "dd-MM-yy", "{0} 3.2.1\r\nStuff done before {0}")] + public void GetModifiedContents_SpecialDatePlaceholderButFileDoesNotSpecifyFormat_InsertsDateWithSpecifiedDateFormat( + string origContents, string dateFormat, string expectedResultFormat) + { + var updater = new FileUpdate + { + Regex = "_VERSION_", + ReplacementText = "3.2.1", + DatePlaceholder = "_DATE(*)_", + DateFormat = dateFormat + }; + + var currentDate = DateTime.UtcNow.Date.ToString(dateFormat ?? updater.DateFormat); + + var result = updater.GetModifiedContents(origContents); + var expectedResult = string.Format(expectedResultFormat, currentDate); + Assert.That(result, Is.EqualTo(expectedResult)); + } + + [TestCase("MM-yy")] + [TestCase("dd MMMM")] + public void GetModifiedContents_SpecialDatePlaceholderWithFileSpecifyingFormat_InsertsDateWithFormatFromFile( + string format) + { + var origContents = $"_DATE({format})_\r\nStuff"; + + var updater = new FileUpdate + { + Regex = "(.*)", + ReplacementText = "$1", + DatePlaceholder = "_DATE(*)_", + }; + + var currentDate = DateTime.UtcNow.Date.ToString(format); + + var result = updater.GetModifiedContents(origContents); + Assert.That(result, Is.EqualTo($"{currentDate}\r\nStuff")); + } + + [TestCase("MM-yyyy", "d MMMM yy")] + [TestCase("dd MMMM", "MM/dd/yyyy")] + public void GetModifiedContents_SpecialDatePlaceholderWithFileSpecifyingMultipleFormats_InsertsDateWithFormatsFromFile( + string format1, string format2) + { + var origContents = $"First _DATE({format1})_\r\nSecond _DATE_\r\nLast _DATE({format2})_"; + + var updater = new FileUpdate + { + Regex = "(.*)", + ReplacementText = "$1", + DatePlaceholder = "_DATE(*)_", + }; + + var currentDate1 = DateTime.UtcNow.Date.ToString(format1); + var currentDateInDefaultFmt = DateTime.UtcNow.Date.ToString(updater.DateFormat); + var currentDate2 = DateTime.UtcNow.Date.ToString(format2); + + var result = updater.GetModifiedContents(origContents); + Assert.That(result, Is.EqualTo($"First {currentDate1}\r\nSecond {currentDateInDefaultFmt}\r\nLast {currentDate2}")); + } + + [TestCase("es")] + [TestCase("fr")] + public void GetModifiedContents_SpecialDatePlaceholderWithLocalizedFileSpecifyingFormat_InsertsLocaleSpecificDateWithFormatFromFile(string locale) + { + var origContents = "_DATE(d MMMM yyyy)_\r\nStuff"; + + var updater = new FileUpdate + { + File = $"ReleaseNotes.{locale}.md", + FileLocalePattern = @"\.(?[a-z]{2}(-\w+)?)\.md$", + Regex = "(.*)", + ReplacementText = "$1", + DatePlaceholder = "_DATE(*)_", + }; + + var currentDate = string.Format(DateTime.UtcNow.Date.ToString("d {0} yyyy"), + GetMonthName(locale, DateTime.UtcNow.Month)); + + var result = updater.GetModifiedContents(origContents); + Assert.That(result, Is.EqualTo($"{currentDate}\r\nStuff")); + } + + private string GetMonthName(string locale, int month) + { + var culture = new CultureInfo(locale); + return culture.DateTimeFormat.GetMonthName(month); + } + [Test] public void GetModifiedContents_InvalidRegex_Throws() { @@ -74,5 +189,89 @@ public void GetModifiedContents_InvalidRegex_Throws() var ex = Assert.Throws(() => updater.GetModifiedContents("Whatever")); Assert.That(ex.Message, Is.EqualTo($"Invalid regular expression: parsing \"{updater.Regex}\" - Not enough )'s.")); } + + [Test] + public void FileLocalePattern_InvalidRegex_ThrowsArgumentException() + { + const string expr = @"ReleaseNotes\.(.*\.md"; + Assert.That(() => + { + _ = new FileUpdate + { + FileLocalePattern = expr, + ReplacementText = "oops" + }; + }, Throws.ArgumentException.With.Message.EqualTo($"FileLocalePattern: Invalid regular expression: parsing \"{expr}\" - Not enough )'s.")); + } + + [TestCase("es")] + [TestCase("fr")] + [TestCase("zh-CN")] + public void GetCultureFromFileName_MatchLocaleGroupToKnownCulture_GetsSpecifiedCulture(string localeSpecifier) + { + var fileUpdater = new FileUpdate + { + File = $"ReleaseNotes.{localeSpecifier}.md", + FileLocalePattern = @"\.(?[a-z]{2}(-\w+)?)\.md$", + }; + + Assert.That(fileUpdater.GetCultureFromFileName().IetfLanguageTag, + Is.EqualTo(localeSpecifier)); + } + + [TestCase("zz-Unknown")] + [TestCase("qq-Weird")] + public void GetCultureFromFileName_MatchLocaleGroupToUnknownCulture_ReturnsNull(string localeSpecifier) + { + var fileUpdater = new FileUpdate + { + File = $"ReleaseNotes.{localeSpecifier}.md", + FileLocalePattern = @"\.(?[a-z]{2}(-\w+)?)\.md$", + }; + + Assert.That(fileUpdater.GetCultureFromFileName(), Is.Null); + } + + [TestCase("es")] + [TestCase("fr-FR")] + [TestCase("de")] + public void GetCultureFromFileName_EntireMatchIsKnownCulture_GetsSpecifiedCulture(string localeSpecifier) + { + var fileUpdater = new FileUpdate + { + File = $"ReleaseNotes.{localeSpecifier}.md", + FileLocalePattern = @"(?<=\.)es|fr-FR|de(?=\.)", + }; + + Assert.That(fileUpdater.GetCultureFromFileName().IetfLanguageTag, + Is.EqualTo(localeSpecifier)); + } + + [TestCase("My.bat.ate.your.homework.md", @"(?<=\.)[a-z]{4}(?=\.)")] + [TestCase("ReleaseNotes.htm", ".+")] + public void GetCultureFromFileName_EntireMatchIsUnknownCulture_ReturnsNull(string fileName, string pattern) + { + var fileUpdater = new FileUpdate + { + File = fileName, + FileLocalePattern = pattern, + }; + + Assert.That(fileUpdater.GetCultureFromFileName(), Is.Null); + } + + [TestCase("My.bat.ate.your.homework.md", @"(?<=\.)[a-z]{22}(?=\.)")] + [TestCase("ReleaseNotes.htm", @"(?<=\.)es|fr-FR|de(?=\.)")] + [TestCase("ReleaseNotes.htm", @"\.(?[a-z]{2}(-\w+)?)\.md$")] + public void GetCultureFromFileName_NoMatch_ReturnsNull(string fileName, string pattern) + { + var fileUpdater = new FileUpdate + { + File = fileName, + FileLocalePattern = pattern, + }; + + Assert.That(fileUpdater.GetCultureFromFileName(), Is.Null); + } } } diff --git a/SIL.BuildTasks/FileUpdate.cs b/SIL.BuildTasks/FileUpdate.cs index e2fd4b32..d13f9dd6 100644 --- a/SIL.BuildTasks/FileUpdate.cs +++ b/SIL.BuildTasks/FileUpdate.cs @@ -1,16 +1,21 @@ -// Copyright (c) 2023 SIL Global +// Copyright (c) 2025 SIL Global // This software is licensed under the MIT License (http://opensource.org/licenses/MIT) using System; using System.Diagnostics; +using System.Globalization; +using System.IO; using System.Text.RegularExpressions; using Microsoft.Build.Framework; using Microsoft.Build.Utilities; +using static System.IO.File; +using static System.Text.RegularExpressions.RegexOptions; namespace SIL.BuildTasks { public class FileUpdate : Task { private string _dateFormat; + private Regex _localeRegex; [Required] public string File { get; set; } @@ -22,12 +27,17 @@ public class FileUpdate : Task public string ReplacementText { get; set; } /// - /// The string pattern to replace with the current date (UTC, dd/MMM/yyyy) + /// The string pattern to replace with the current date. If this is specified as + /// `_DATE(*)_`, then this will be treated as a regex that will match `_DATE_` as well as + /// any string that matches _DATE?<?dateFormat?>([dMy/:.,\-\s']+)_, in which case + /// the `dateFormat` match group will be used to format the date instead of + /// . /// public string DatePlaceholder { get; set; } /// - /// The date format to output (default is dd/MMM/yyyy) + /// Default date format, used unless the finds a match that + /// specifies an alternate format. /// public string DateFormat { @@ -35,19 +45,46 @@ public string DateFormat set => _dateFormat = value; } + /// + /// Optional regex pattern with a named group 'locale' to extract the locale from the + /// filename. + /// Example: @"\.(?<locale>[a-z]{2}(-\w+)?)\.md$" to match "es", "fr", "zh-CN", etc., + /// between dots and preceding the final md (markdown) extension. + /// If there is no named group 'locale', then the entire match will be treated + /// as the locale. + /// Example: @"(?<=\.).es|fr|de(?=\.)" + /// + /// The given pattern is not a well-formed regular expression + /// If the pattern matches more than once, the first match will be used. + public string FileLocalePattern + { + get => _localeRegex?.ToString(); + set + { + try + { + _localeRegex = string.IsNullOrEmpty(value) ? null : new Regex(value); + } + catch (ArgumentException e) + { + throw new ArgumentException("FileLocalePattern: Invalid regular expression: " + e.Message, e); + } + } + } + public override bool Execute() { try { - var content = System.IO.File.ReadAllText(File); + var content = ReadAllText(File); var newContents = GetModifiedContents(content); - System.IO.File.WriteAllText(File, newContents); + WriteAllText(File, newContents); return true; } catch (Exception e) { Console.WriteLine(e); - Debug.WriteLine(e.Message); + Debug.WriteLine(e); SafeLogError(e.Message); return false; } @@ -78,7 +115,27 @@ internal string GetModifiedContents(string content) var newContents = regex.Replace(content, ReplacementText); if (!string.IsNullOrEmpty(DatePlaceholder)) - newContents = newContents.Replace(DatePlaceholder, DateTime.UtcNow.Date.ToString(DateFormat)); + { + var culture = GetCultureFromFileName() ?? CultureInfo.CurrentCulture; + + if (DatePlaceholder.Equals("_DATE(*)_", StringComparison.Ordinal)) + { + var dateRegex = new Regex( + @"_DATE(\((?[dMy\/:.,\-\s'M]+)\))?_", Compiled); + newContents = dateRegex.Replace(newContents, m => + { + var format = m.Groups["dateFormat"].Success + ? m.Groups["dateFormat"].Value + : DateFormat; + return DateTime.UtcNow.Date.ToString(format, culture); + }); + } + else + { + var formattedDate = DateTime.UtcNow.Date.ToString(DateFormat, culture); + newContents = newContents.Replace(DatePlaceholder, formattedDate); + } + } return newContents; } @@ -88,6 +145,36 @@ internal string GetModifiedContents(string content) } } + internal CultureInfo GetCultureFromFileName() + { + if (_localeRegex == null) + return null; + + var fileName = Path.GetFileName(File); + + try + { + var match = _localeRegex.Match(fileName); + if (match.Success) + { + var locale = match.Groups["locale"].Success + ? match.Groups["locale"].Value + : match.Value; + return new CultureInfo(locale); + } + } + catch (CultureNotFoundException) + { + } + catch (Exception ex) + { + SafeLogError( + $"Failed to extract locale from filename using pattern '{FileLocalePattern}': {ex.Message}"); + } + + return null; + } + private void SafeLogError(string msg) { try @@ -96,8 +183,8 @@ private void SafeLogError(string msg) } catch (Exception) { - //swallow... logging fails in the unit test environment, where the log isn't really set up + //swallow... logging fails in the unit test environment, where the log isn't set up } } } -} \ No newline at end of file +} From e2a8b9c0edf7ef80df92fd010a833f9afe7905e1 Mon Sep 17 00:00:00 2001 From: tombogle Date: Tue, 27 May 2025 12:13:46 -0400 Subject: [PATCH 2/2] Used DateTimeProvider and (in tests) ReproducibleDateTimeProvider to simplify unit tests Note that I intentionally used a very old version of the new dependencies because it was all I needed and I figured it might help avoid --- SIL.BuildTasks.Tests/FileUpdateTests.cs | 71 ++++++++++--------- .../SIL.BuildTasks.Tests.csproj | 1 + SIL.BuildTasks/FileUpdate.cs | 6 +- SIL.BuildTasks/SIL.BuildTasks.csproj | 1 + 4 files changed, 42 insertions(+), 37 deletions(-) diff --git a/SIL.BuildTasks.Tests/FileUpdateTests.cs b/SIL.BuildTasks.Tests/FileUpdateTests.cs index 052ddad1..fabdd175 100644 --- a/SIL.BuildTasks.Tests/FileUpdateTests.cs +++ b/SIL.BuildTasks.Tests/FileUpdateTests.cs @@ -1,9 +1,11 @@ -// Copyright (c) 2024 SIL Global +// Copyright (c) 2025 SIL Global // This software is licensed under the MIT License (http://opensource.org/licenses/MIT) using System; -using System.Globalization; using NUnit.Framework; +using SIL.Providers; +using SIL.TestUtilities.Providers; + // Sadly, Resharper wants to change Is.EqualTo to NUnit.Framework.Is.EqualTo // ReSharper disable AccessToStaticMemberViaDerivedType @@ -12,6 +14,19 @@ namespace SIL.BuildTasks.Tests [TestFixture] public class FileUpdateTests { + [SetUp] + public void Setup() + { + DateTimeProvider.SetProvider( + new ReproducibleDateTimeProvider(new DateTime(2026, 4, 16))); + } + + [TearDown] + public void TearDown() + { + DateTimeProvider.ResetToDefault(); + } + [TestCase("This is the story of the frog prince.", "frog", "monkey", ExpectedResult = "This is the story of the monkey prince.")] [TestCase("This is the story of the frog prince.", "f[^ ]+g", "toad", @@ -63,14 +78,14 @@ public void GetModifiedContents_RegexTextNotMatched_Throws(string origContents, Assert.That(ex.Message, Is.EqualTo($"No replacements made. Regex: '{regex}'; ReplacementText: '{replacement}'")); } - [TestCase("_DATE_ _VERSION_\r\nStuff", "_DATE_", "M/yyyy", "{0} 3.2.1\r\nStuff")] - [TestCase("_DATE_ _VERSION_\r\nStuff done before _DATE_", "_DATE_", "M/yyyy", "{0} 3.2.1\r\nStuff done before {0}")] - [TestCase("&DATE; _VERSION_\r\n- point #1", "&DATE;", "dd-MM-yy", "{0} 3.2.1\r\n- point #1")] - [TestCase("DATE _VERSION_", "DATE", "dd MMMM, yyyy", "{0} 3.2.1")] - [TestCase("DATE _VERSION_", "DATE", null, "{0} 3.2.1")] + [TestCase("_DATE_ _VERSION_\r\nStuff", "_DATE_", "M/yyyy", "4/2026 3.2.1\r\nStuff")] + [TestCase("_DATE_ _VERSION_\r\nStuff done before _DATE_", "_DATE_", "M/yyyy", "4/2026 3.2.1\r\nStuff done before 4/2026")] + [TestCase("&DATE; _VERSION_\r\n- point #1", "&DATE;", "dd-MM-yy", "16-04-26 3.2.1\r\n- point #1")] + [TestCase("DATE _VERSION_", "DATE", "dd MMMM, yyyy", "16 April, 2026 3.2.1")] + [TestCase("DATE _VERSION_", "DATE", null, "16/Apr/2026 3.2.1")] // Uses default date format public void GetModifiedContents_DateLiteral_InsertsDateWithSpecifiedDateFormat( string origContents, string datePlaceholder, string dateFormat, - string expectedResultFormat) + string expectedResult) { var updater = new FileUpdate { @@ -80,17 +95,14 @@ public void GetModifiedContents_DateLiteral_InsertsDateWithSpecifiedDateFormat( DateFormat = dateFormat }; - var currentDate = DateTime.UtcNow.Date.ToString(dateFormat ?? updater.DateFormat); - var result = updater.GetModifiedContents(origContents); - var expectedResult = string.Format(expectedResultFormat, currentDate); Assert.That(result, Is.EqualTo(expectedResult)); } - [TestCase("_DATE_ _VERSION_\r\nStuff", "M/yyyy", "{0} 3.2.1\r\nStuff")] - [TestCase("_DATE_ _VERSION_\r\nStuff done before _DATE_", "dd-MM-yy", "{0} 3.2.1\r\nStuff done before {0}")] + [TestCase("_DATE_ _VERSION_\r\nStuff", "M/yyyy", "4/2026 3.2.1\r\nStuff")] + [TestCase("_DATE_ _VERSION_\r\nStuff done before _DATE_", "dd-MM-yy", "16-04-26 3.2.1\r\nStuff done before 16-04-26")] public void GetModifiedContents_SpecialDatePlaceholderButFileDoesNotSpecifyFormat_InsertsDateWithSpecifiedDateFormat( - string origContents, string dateFormat, string expectedResultFormat) + string origContents, string dateFormat, string expectedResult) { var updater = new FileUpdate { @@ -100,10 +112,7 @@ public void GetModifiedContents_SpecialDatePlaceholderButFileDoesNotSpecifyForma DateFormat = dateFormat }; - var currentDate = DateTime.UtcNow.Date.ToString(dateFormat ?? updater.DateFormat); - var result = updater.GetModifiedContents(origContents); - var expectedResult = string.Format(expectedResultFormat, currentDate); Assert.That(result, Is.EqualTo(expectedResult)); } @@ -121,7 +130,7 @@ public void GetModifiedContents_SpecialDatePlaceholderWithFileSpecifyingFormat_I DatePlaceholder = "_DATE(*)_", }; - var currentDate = DateTime.UtcNow.Date.ToString(format); + var currentDate = DateTimeProvider.Current.UtcNow.ToString(format); var result = updater.GetModifiedContents(origContents); Assert.That(result, Is.EqualTo($"{currentDate}\r\nStuff")); @@ -141,17 +150,18 @@ public void GetModifiedContents_SpecialDatePlaceholderWithFileSpecifyingMultiple DatePlaceholder = "_DATE(*)_", }; - var currentDate1 = DateTime.UtcNow.Date.ToString(format1); - var currentDateInDefaultFmt = DateTime.UtcNow.Date.ToString(updater.DateFormat); - var currentDate2 = DateTime.UtcNow.Date.ToString(format2); + var currentDate = DateTimeProvider.Current.UtcNow; + var currentDate1 = currentDate.ToString(format1); + var currentDate2 = currentDate.ToString(format2); var result = updater.GetModifiedContents(origContents); - Assert.That(result, Is.EqualTo($"First {currentDate1}\r\nSecond {currentDateInDefaultFmt}\r\nLast {currentDate2}")); + Assert.That(result, Is.EqualTo($"First {currentDate1}\r\nSecond 16/Apr/2026\r\nLast {currentDate2}")); } - [TestCase("es")] - [TestCase("fr")] - public void GetModifiedContents_SpecialDatePlaceholderWithLocalizedFileSpecifyingFormat_InsertsLocaleSpecificDateWithFormatFromFile(string locale) + [TestCase("es", "abril")] + [TestCase("fr", "avril")] + public void GetModifiedContents_SpecialDatePlaceholderWithLocalizedFileSpecifyingFormat_InsertsLocaleSpecificDateWithFormatFromFile( + string locale, string localizedMonthName) { var origContents = "_DATE(d MMMM yyyy)_\r\nStuff"; @@ -164,17 +174,8 @@ public void GetModifiedContents_SpecialDatePlaceholderWithLocalizedFileSpecifyin DatePlaceholder = "_DATE(*)_", }; - var currentDate = string.Format(DateTime.UtcNow.Date.ToString("d {0} yyyy"), - GetMonthName(locale, DateTime.UtcNow.Month)); - var result = updater.GetModifiedContents(origContents); - Assert.That(result, Is.EqualTo($"{currentDate}\r\nStuff")); - } - - private string GetMonthName(string locale, int month) - { - var culture = new CultureInfo(locale); - return culture.DateTimeFormat.GetMonthName(month); + Assert.That(result, Is.EqualTo($"16 {localizedMonthName} 2026\r\nStuff")); } [Test] diff --git a/SIL.BuildTasks.Tests/SIL.BuildTasks.Tests.csproj b/SIL.BuildTasks.Tests/SIL.BuildTasks.Tests.csproj index 4417d671..76203f07 100644 --- a/SIL.BuildTasks.Tests/SIL.BuildTasks.Tests.csproj +++ b/SIL.BuildTasks.Tests/SIL.BuildTasks.Tests.csproj @@ -20,6 +20,7 @@ + diff --git a/SIL.BuildTasks/FileUpdate.cs b/SIL.BuildTasks/FileUpdate.cs index d13f9dd6..effccf55 100644 --- a/SIL.BuildTasks/FileUpdate.cs +++ b/SIL.BuildTasks/FileUpdate.cs @@ -7,6 +7,7 @@ using System.Text.RegularExpressions; using Microsoft.Build.Framework; using Microsoft.Build.Utilities; +using SIL.Providers; using static System.IO.File; using static System.Text.RegularExpressions.RegexOptions; @@ -117,6 +118,7 @@ internal string GetModifiedContents(string content) if (!string.IsNullOrEmpty(DatePlaceholder)) { var culture = GetCultureFromFileName() ?? CultureInfo.CurrentCulture; + var currentDate = DateTimeProvider.Current.UtcNow.Date; if (DatePlaceholder.Equals("_DATE(*)_", StringComparison.Ordinal)) { @@ -127,12 +129,12 @@ internal string GetModifiedContents(string content) var format = m.Groups["dateFormat"].Success ? m.Groups["dateFormat"].Value : DateFormat; - return DateTime.UtcNow.Date.ToString(format, culture); + return currentDate.ToString(format, culture); }); } else { - var formattedDate = DateTime.UtcNow.Date.ToString(DateFormat, culture); + var formattedDate = currentDate.ToString(DateFormat, culture); newContents = newContents.Replace(DatePlaceholder, formattedDate); } } diff --git a/SIL.BuildTasks/SIL.BuildTasks.csproj b/SIL.BuildTasks/SIL.BuildTasks.csproj index b258aeb4..a9defc0f 100644 --- a/SIL.BuildTasks/SIL.BuildTasks.csproj +++ b/SIL.BuildTasks/SIL.BuildTasks.csproj @@ -9,6 +9,7 @@ +