From 68b667304e926ff5e5f3aff4ce23afa70308e55d Mon Sep 17 00:00:00 2001 From: Hector Mendoza Jacobo Date: Tue, 11 Feb 2025 18:23:39 -0500 Subject: [PATCH 1/3] feat: Add the interval type --- .../V1/IntervalTests.cs | 112 ++++++ .../Google.Cloud.Spanner.V1/Interval.cs | 325 ++++++++++++++++++ 2 files changed, 437 insertions(+) create mode 100644 apis/Google.Cloud.Spanner.Data/Google.Cloud.Spanner.Data.Tests/V1/IntervalTests.cs create mode 100644 apis/Google.Cloud.Spanner.V1/Google.Cloud.Spanner.V1/Interval.cs diff --git a/apis/Google.Cloud.Spanner.Data/Google.Cloud.Spanner.Data.Tests/V1/IntervalTests.cs b/apis/Google.Cloud.Spanner.Data/Google.Cloud.Spanner.Data.Tests/V1/IntervalTests.cs new file mode 100644 index 000000000000..b08439d8ac59 --- /dev/null +++ b/apis/Google.Cloud.Spanner.Data/Google.Cloud.Spanner.Data.Tests/V1/IntervalTests.cs @@ -0,0 +1,112 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using Microsoft.VisualBasic; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Numerics; +using System.Threading; +using Xunit; + +namespace Google.Cloud.Spanner.V1.Tests +{ + public class IntervalTests + { + [Theory] + [InlineData("P-0Y", "P0Y")] + [InlineData("P0Y0M0DT0H0M0S", "P0Y")] + [InlineData("P16M", "P1Y4M")] + [InlineData("P2Y-2M", "P1Y10M")] + [InlineData("P-1Y2M", "P-10M")] + [InlineData("P372D", "P372D")] + [InlineData("P-372D", "P-372D")] + [InlineData("PT7200H", "PT7200H")] + [InlineData("PT1H69M72S", "PT2H10M12S")] + [InlineData("PT1H-5M-2S", "PT54M58S")] + [InlineData("PT0,5S", "PT0.5S")] + [InlineData("PT0.500S", "PT0.5S")] + [InlineData("PT.5S", "PT0.5S")] + public void ParseString(string intervalString, string expectedString) + { + Interval interval = new Interval(intervalString); + Assert.Equal(interval.ToIso8601(), expectedString); + } + + [Theory] + [InlineData("P1Y", Interval.NanosecondsInAYear)] + [InlineData("P12M", Interval.NanosecondsInAYear)] + [InlineData("P1M", Interval.NanosecondsInAMonth)] + [InlineData("PT1H", Interval.NanosecondsInAnHour)] + [InlineData("PT60M", Interval.NanosecondsInAnHour)] + [InlineData("PT1M", Interval.NanosecondsInAMinute)] + [InlineData("PT1S", Interval.NanosecondsInASecond)] + [InlineData("PT0.000000001S", 1L)] + public void GetNanoseconds(string intervalString, long expectedNanoseconds) + { + Interval interval = new Interval(intervalString); + Assert.Equal(interval.ToNanoseconds(), expectedNanoseconds); + } + + [Theory] + [InlineData("P10Y", "P1Y", 1)] + [InlineData("P10Y", "P10Y", 0)] + [InlineData("P1Y", "P10Y", -1)] + [InlineData("P1Y", "P1Y1M", -1)] + [InlineData("P10M", "P1M", 1)] + [InlineData("P10M", "P100M", -1)] + [InlineData("P10M", "P10M", 0)] + [InlineData("P10M1D", "P10M", 1)] + [InlineData("P10MT1H", "P10M", 1)] + [InlineData("P10D", "P10D", 0)] + [InlineData("P1D", "P10D", -1)] + [InlineData("P10D", "P1D", 1)] + [InlineData("P1DT1S", "P1D", 1)] + [InlineData("PT1H", "PT2H", -1)] + [InlineData("PT2H1M", "PT2H", 1)] + [InlineData("PT1S", "PT2S", -1)] + [InlineData("PT0.000000001S", "PT0.000000002S", -1)] + [InlineData("PT1S", "PT-1S", 1)] + public void CompareTest(string intervalString1, string intervalString2, int expectedResult) + { + Interval interval1 = new Interval(intervalString1); + Interval interval2 = new Interval(intervalString2); + Assert.Equal(interval1.CompareTo(interval2), expectedResult); + } + + [Theory] + [InlineData("P0.5Y")] + [InlineData("P0.5M")] + [InlineData("P0.5D")] + [InlineData("PT0.5H")] + [InlineData("PT0.5M")] + [InlineData("P5S")] + [InlineData("P1Y3S")] + [InlineData("P1YT3M1")] + [InlineData("P1YT3M1.1.4S")] + [InlineData("")] + [InlineData("P")] + [InlineData("PT")] + [InlineData("PTS")] + [InlineData("PY")] + [InlineData("PM")] + [InlineData("PD")] + [InlineData("PTH")] + [InlineData("PTM")] + public void InvalidString(string intervalString) + { + Assert.Throws(() => new Interval(intervalString)); + } + } +} diff --git a/apis/Google.Cloud.Spanner.V1/Google.Cloud.Spanner.V1/Interval.cs b/apis/Google.Cloud.Spanner.V1/Google.Cloud.Spanner.V1/Interval.cs new file mode 100644 index 000000000000..435ba4b9458b --- /dev/null +++ b/apis/Google.Cloud.Spanner.V1/Google.Cloud.Spanner.V1/Interval.cs @@ -0,0 +1,325 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System; +using System.Linq; +using System.Numerics; + +namespace Google.Cloud.Spanner.V1 +{ + /// + /// Representation of a Time Interval + /// + public class Interval : IComparable + { + /// + /// Months contained in the interval + /// + public int Months { get; private set; } = 0; + /// + /// Days contained in the interval + /// + public int Days { get; private set; } = 0; + /// + /// Nanoseconds contained in the interval + /// + public BigInteger Nanoseconds { get; private set; } = 0; + private const int Uninitialized = 0; + private const int ParsingDate = 1; + private const int ParsingTime = 2; + /// + /// Nanoseconds in one second + /// + public const long NanosecondsInASecond = 1000000000L; + /// + /// Nanoseconds in one minute + /// + public const long NanosecondsInAMinute = NanosecondsInASecond * 60; + /// + /// Nanoseconds in one in one hour + /// + public const long NanosecondsInAnHour = NanosecondsInAMinute * 60; + /// + /// Nanoseconds in one day + /// + public const long NanosecondsInADay = NanosecondsInAnHour * 24; + /// + /// Nanoseconds in one month + /// + public const long NanosecondsInAMonth = NanosecondsInADay * 30; + /// + /// Nanoseconds in one year + /// + public const long NanosecondsInAYear = NanosecondsInAMonth * 12; + + /// + /// Representation of a Time Interval + /// + public Interval(string interval) + { + int state = 0; + bool complete = false; + string count = ""; + + foreach (char c in interval) { + if (state == Uninitialized) { + if (c != 'P') { + throw new FormatException("Invalid Format"); + } + + state = ParsingDate; + continue; + } + + if (c == 'T') { + complete = false; + state = ParsingTime; + continue; + } + + if (char.IsDigit(c) || c == '-' || c == '.' || c == ',') { + complete = false; + count += c == ',' ? '.' : c; + continue; + } + + if (state == ParsingDate) { + if (!this.validateInt(count)) { + throw new FormatException("Invalid Format"); + } + + switch (c) { + case 'Y': + this.Months += this.YearsToMonths(count); + break; + case 'M': + this.Months += int.Parse(count); + break; + case 'D': + this.Days = int.Parse(count); + break; + default: + throw new FormatException("Invalid Format"); + } + + count = ""; + complete = true; + continue; + } + + if (state == ParsingTime) { + switch (c) { + case 'H': + this.Nanoseconds += this.HoursToNanoseconds(count); + break; + case 'M': + this.Nanoseconds += this.MinutesToNanoseconds(count); + break; + case 'S': + this.Nanoseconds += this.SecondsToNanoseconds(count); + break; + default: + throw new FormatException("Invalid Format"); + } + + count = ""; + complete = true; + continue; + } + } + + if (!complete) { + throw new FormatException("Invalid Format"); + } + } + + /// + /// Converts the current interval into an ISO8601 string + /// + public string ToIso8601() + { + int years; + int months; + int days = this.Days; + int hours; + int minutes; + float seconds; + BigInteger remainingNanoseconds = this.Nanoseconds; + + years = this.Months / 12; + months = this.Months % 12; + hours = (int) (remainingNanoseconds / 3600000000000); + remainingNanoseconds %= 3600000000000; + minutes = (int) (remainingNanoseconds / 60000000000); + remainingNanoseconds %= 60000000000; + seconds = (float) remainingNanoseconds / 1000000000; + + string intervalString = "P"; + + if (years != 0) { + intervalString += $"{years}Y"; + } + + if (months != 0) { + intervalString += $"{months}M"; + } + + if (days != 0) { + intervalString += $"{days}D"; + } + + if (hours != 0 || minutes != 0 || seconds != 0) { + intervalString += "T"; + + if (hours != 0) { + intervalString += $"{hours}H"; + } + + if (minutes != 0) { + intervalString += $"{minutes}M"; + } + + if (seconds != 0) { + intervalString += $"{seconds}S"; + } + } + + if (intervalString == "P") { + return "P0Y"; + } + + return intervalString; + } + + /// + /// Compares one interval to another interval + /// + public int CompareTo(Interval other) + { + return this.ToNanoseconds().CompareTo(other.ToNanoseconds()); + } + + /// + /// Converts the current interval to Nanoseconds + /// + public BigInteger ToNanoseconds() + { + BigInteger nanoseconds = 0; + nanoseconds += (BigInteger) (this.Months * NanosecondsInAMonth); + nanoseconds += this.Days * NanosecondsInADay; + nanoseconds += this.Nanoseconds; + + return nanoseconds; + } + + /// + /// Creates an interval based on Months, Days and Nanoseconds + /// + public static Interval FromMonthsDaysNanos(int months, int days, BigInteger nanos) + { + Interval interval = new Interval("P0Y"); + interval.Months = months; + interval.Days = days; + interval.Nanoseconds = nanos; + + return interval; + } + + /// + /// Creates an interval based on the Months given + /// + public static Interval OfMonths(int months) + { + return new Interval($"P{months}M"); + } + + /// + /// Creates an Interval based on the Days given + /// + public static Interval OfDays(int days) + { + return new Interval($"P{days}D"); + } + + /// + /// Creates an Interval based on the seconds given + /// + public static Interval ofSeconds(int seconds) + { + return new Interval($"PT{seconds}S"); + } + + /// + /// Creates an Interval based on the milliseconds given + /// + public static Interval ofMilliseconds(long milliseconds) + { + return new Interval($"PT{(decimal) milliseconds / 1000}S"); + } + + /// + /// Creates an Interval based on the microseconds given + /// + public static Interval ofMicroseconds(long microseconds) + { + return new Interval($"PT{(decimal) microseconds / 1000000}S"); + } + + /// + /// Creates an Interval based on the nanoseconds given + /// + public static Interval ofNanoseconds(ulong nanoseconds) + { + return new Interval($"PT{(decimal) nanoseconds / 1000000000}S"); + } + + + private int YearsToMonths(string years) + { + return int.Parse(years) * 12; + } + + private BigInteger HoursToNanoseconds(string hours) + { + return BigInteger.Parse(hours) * NanosecondsInAnHour; + } + + private BigInteger MinutesToNanoseconds(string minutes) + { + return BigInteger.Parse(minutes) * NanosecondsInAMinute; + } + + private BigInteger SecondsToNanoseconds(string seconds) + { + string[] splitNumber = seconds.Split('.'); + + if (splitNumber.Length > 2) { + throw new FormatException("Invalid Format"); + } + + decimal nanoseconds = decimal.Parse(seconds) * NanosecondsInASecond; + + return (BigInteger) nanoseconds; + } + + private bool validateInt(string number) + { + if (number.Contains('.')) { + return false; + } + + return true; + } + } +} From 9008a2c632cc85327ddd1ea69b65eca933fa1663 Mon Sep 17 00:00:00 2001 From: Hector Mendoza Jacobo Date: Thu, 20 Feb 2025 16:29:02 -0500 Subject: [PATCH 2/3] Modify the Interval to make use of a Regex --- .../V1/IntervalTests.cs | 49 +-- .../Google.Cloud.Spanner.V1/Interval.cs | 286 +++++++----------- 2 files changed, 112 insertions(+), 223 deletions(-) diff --git a/apis/Google.Cloud.Spanner.Data/Google.Cloud.Spanner.Data.Tests/V1/IntervalTests.cs b/apis/Google.Cloud.Spanner.Data/Google.Cloud.Spanner.Data.Tests/V1/IntervalTests.cs index b08439d8ac59..b7c30ee2f5e3 100644 --- a/apis/Google.Cloud.Spanner.Data/Google.Cloud.Spanner.Data.Tests/V1/IntervalTests.cs +++ b/apis/Google.Cloud.Spanner.Data/Google.Cloud.Spanner.Data.Tests/V1/IntervalTests.cs @@ -35,54 +35,13 @@ public class IntervalTests [InlineData("PT7200H", "PT7200H")] [InlineData("PT1H69M72S", "PT2H10M12S")] [InlineData("PT1H-5M-2S", "PT54M58S")] - [InlineData("PT0,5S", "PT0.5S")] + [InlineData("PT0.5S", "PT0.5S")] [InlineData("PT0.500S", "PT0.5S")] [InlineData("PT.5S", "PT0.5S")] public void ParseString(string intervalString, string expectedString) { - Interval interval = new Interval(intervalString); - Assert.Equal(interval.ToIso8601(), expectedString); - } - - [Theory] - [InlineData("P1Y", Interval.NanosecondsInAYear)] - [InlineData("P12M", Interval.NanosecondsInAYear)] - [InlineData("P1M", Interval.NanosecondsInAMonth)] - [InlineData("PT1H", Interval.NanosecondsInAnHour)] - [InlineData("PT60M", Interval.NanosecondsInAnHour)] - [InlineData("PT1M", Interval.NanosecondsInAMinute)] - [InlineData("PT1S", Interval.NanosecondsInASecond)] - [InlineData("PT0.000000001S", 1L)] - public void GetNanoseconds(string intervalString, long expectedNanoseconds) - { - Interval interval = new Interval(intervalString); - Assert.Equal(interval.ToNanoseconds(), expectedNanoseconds); - } - - [Theory] - [InlineData("P10Y", "P1Y", 1)] - [InlineData("P10Y", "P10Y", 0)] - [InlineData("P1Y", "P10Y", -1)] - [InlineData("P1Y", "P1Y1M", -1)] - [InlineData("P10M", "P1M", 1)] - [InlineData("P10M", "P100M", -1)] - [InlineData("P10M", "P10M", 0)] - [InlineData("P10M1D", "P10M", 1)] - [InlineData("P10MT1H", "P10M", 1)] - [InlineData("P10D", "P10D", 0)] - [InlineData("P1D", "P10D", -1)] - [InlineData("P10D", "P1D", 1)] - [InlineData("P1DT1S", "P1D", 1)] - [InlineData("PT1H", "PT2H", -1)] - [InlineData("PT2H1M", "PT2H", 1)] - [InlineData("PT1S", "PT2S", -1)] - [InlineData("PT0.000000001S", "PT0.000000002S", -1)] - [InlineData("PT1S", "PT-1S", 1)] - public void CompareTest(string intervalString1, string intervalString2, int expectedResult) - { - Interval interval1 = new Interval(intervalString1); - Interval interval2 = new Interval(intervalString2); - Assert.Equal(interval1.CompareTo(interval2), expectedResult); + Interval interval = Interval.FromIso8601String(intervalString); + Assert.Equal(interval.ToString(), expectedString); } [Theory] @@ -106,7 +65,7 @@ public void CompareTest(string intervalString1, string intervalString2, int expe [InlineData("PTM")] public void InvalidString(string intervalString) { - Assert.Throws(() => new Interval(intervalString)); + Assert.Throws(() => Interval.FromIso8601String(intervalString)); } } } diff --git a/apis/Google.Cloud.Spanner.V1/Google.Cloud.Spanner.V1/Interval.cs b/apis/Google.Cloud.Spanner.V1/Google.Cloud.Spanner.V1/Interval.cs index 435ba4b9458b..ed8453bf3a84 100644 --- a/apis/Google.Cloud.Spanner.V1/Google.Cloud.Spanner.V1/Interval.cs +++ b/apis/Google.Cloud.Spanner.V1/Google.Cloud.Spanner.V1/Interval.cs @@ -13,141 +13,117 @@ // limitations under the License. using System; +using System.Collections.Generic; using System.Linq; using System.Numerics; +using System.Text.RegularExpressions; namespace Google.Cloud.Spanner.V1 { /// /// Representation of a Time Interval /// - public class Interval : IComparable + public class Interval { - /// - /// Months contained in the interval - /// - public int Months { get; private set; } = 0; - /// - /// Days contained in the interval - /// - public int Days { get; private set; } = 0; - /// - /// Nanoseconds contained in the interval - /// - public BigInteger Nanoseconds { get; private set; } = 0; private const int Uninitialized = 0; private const int ParsingDate = 1; private const int ParsingTime = 2; + internal const long NanosecondsInASecond = 1000000000L; + internal const long NanosecondsInAMinute = NanosecondsInASecond * 60; + internal const long NanosecondsInAnHour = NanosecondsInAMinute * 60; + internal const long NanosecondsInADay = NanosecondsInAnHour * 24; + internal const long NanosecondsInAMonth = NanosecondsInADay * 30; + internal const long NanosecondsInAYear = NanosecondsInAMonth * 12; + internal const long NanosecondsInAMillisecond = 1000000L; + internal const long NanosecondsInAMicrosecond = 1000L; + /// - /// Nanoseconds in one second - /// - public const long NanosecondsInASecond = 1000000000L; - /// - /// Nanoseconds in one minute - /// - public const long NanosecondsInAMinute = NanosecondsInASecond * 60; - /// - /// Nanoseconds in one in one hour - /// - public const long NanosecondsInAnHour = NanosecondsInAMinute * 60; - /// - /// Nanoseconds in one day + /// Months contained in the interval /// - public const long NanosecondsInADay = NanosecondsInAnHour * 24; + public int Months { get; set; } = 0; + /// - /// Nanoseconds in one month + /// Days contained in the interval /// - public const long NanosecondsInAMonth = NanosecondsInADay * 30; + public int Days { get; set; } = 0; + /// - /// Nanoseconds in one year + /// Nanoseconds contained in the interval /// - public const long NanosecondsInAYear = NanosecondsInAMonth * 12; + public BigInteger Nanoseconds { get; set; } = 0; /// /// Representation of a Time Interval /// - public Interval(string interval) + private Interval(int months, int days, BigInteger nanoseconds) { - int state = 0; - bool complete = false; - string count = ""; + this.Months = months; + this.Days = days; + this.Nanoseconds = nanoseconds; + } - foreach (char c in interval) { - if (state == Uninitialized) { - if (c != 'P') { - throw new FormatException("Invalid Format"); - } + /// + /// Constructs + /// + public static Interval FromIso8601String(string intervalString) + { + const int Years = 1, Months = 2, Days = 3, Hours = 5, Minutes = 6, Seconds = 7; + HashSet groupNames = new HashSet{Years, Months, Days, Hours, Minutes, Seconds}; + string isoPattern = @"^P(?!$)(-?\d+Y)?(-?\d+M)?(-?\d+D)?(T(?=-?.?\d)(-?\d+H)?(-?\d+M)?(-?(((\d*)((\.|,)\d{1,9})?)|(\.\d{1,9}))S)?)?$"; - state = ParsingDate; - continue; - } + int calculatedMonths = 0; + int calculatedDays = 0; + BigInteger calculatedNanoseconds = 0; - if (c == 'T') { - complete = false; - state = ParsingTime; - continue; - } + MatchCollection matches = Regex.Matches(intervalString, isoPattern); + if (matches.Count != 1) { + throw new FormatException("Invalid Format"); + } - if (char.IsDigit(c) || c == '-' || c == '.' || c == ',') { - complete = false; - count += c == ',' ? '.' : c; + int index = 0; + foreach (Group group in matches[0].Groups) { + if (!groupNames.Contains(index)) { + index++; continue; } - if (state == ParsingDate) { - if (!this.validateInt(count)) { - throw new FormatException("Invalid Format"); - } - - switch (c) { - case 'Y': - this.Months += this.YearsToMonths(count); - break; - case 'M': - this.Months += int.Parse(count); - break; - case 'D': - this.Days = int.Parse(count); - break; - default: - throw new FormatException("Invalid Format"); - } - - count = ""; - complete = true; + if (group.Value == "") { + index++; continue; } - if (state == ParsingTime) { - switch (c) { - case 'H': - this.Nanoseconds += this.HoursToNanoseconds(count); - break; - case 'M': - this.Nanoseconds += this.MinutesToNanoseconds(count); - break; - case 'S': - this.Nanoseconds += this.SecondsToNanoseconds(count); - break; - default: - throw new FormatException("Invalid Format"); - } - - count = ""; - complete = true; - continue; + // Stripping the letters out of the match group + string numericString = Regex.Replace(group.Value, "[^0-9.,-]", ""); + switch (index) { + case Years: + calculatedMonths += Interval.YearsToMonths(numericString); + break; + case Months: + calculatedMonths += int.Parse(numericString); + break; + case Days: + calculatedDays = int.Parse(numericString); + break; + case Hours: + calculatedNanoseconds += Interval.HoursToNanoseconds(numericString); + break; + case Minutes: + calculatedNanoseconds += Interval.MinutesToNanoseconds(numericString); + break; + case Seconds: + calculatedNanoseconds += Interval.SecondsToNanoseconds(numericString); + break; } + index++; } - if (!complete) { - throw new FormatException("Invalid Format"); - } + return new Interval(calculatedMonths, calculatedDays, calculatedNanoseconds); } /// /// Converts the current interval into an ISO8601 string /// - public string ToIso8601() + public override string ToString() { int years; int months; @@ -167,35 +143,43 @@ public string ToIso8601() string intervalString = "P"; - if (years != 0) { + if (years != 0) + { intervalString += $"{years}Y"; } - if (months != 0) { + if (months != 0) + { intervalString += $"{months}M"; } - if (days != 0) { + if (days != 0) + { intervalString += $"{days}D"; } - if (hours != 0 || minutes != 0 || seconds != 0) { + if (hours != 0 || minutes != 0 || seconds != 0) + { intervalString += "T"; - if (hours != 0) { + if (hours != 0) + { intervalString += $"{hours}H"; } - if (minutes != 0) { + if (minutes != 0) + { intervalString += $"{minutes}M"; } - if (seconds != 0) { + if (seconds != 0) + { intervalString += $"{seconds}S"; } } - if (intervalString == "P") { + if (intervalString == "P") + { return "P0Y"; } @@ -203,108 +187,53 @@ public string ToIso8601() } /// - /// Compares one interval to another interval + /// Creates an interval based on Months, Days and Nanoseconds. /// - public int CompareTo(Interval other) - { - return this.ToNanoseconds().CompareTo(other.ToNanoseconds()); - } + public static Interval FromMonthsDaysNanos(int months, int days, BigInteger nanos) => new Interval(months, days, nanos); /// - /// Converts the current interval to Nanoseconds + /// Creates an interval based on the Months given. /// - public BigInteger ToNanoseconds() - { - BigInteger nanoseconds = 0; - nanoseconds += (BigInteger) (this.Months * NanosecondsInAMonth); - nanoseconds += this.Days * NanosecondsInADay; - nanoseconds += this.Nanoseconds; - - return nanoseconds; - } + public static Interval FromMonths(int months) => new Interval(months, 0, 0); /// - /// Creates an interval based on Months, Days and Nanoseconds + /// Creates an Interval based on the Days given. /// - public static Interval FromMonthsDaysNanos(int months, int days, BigInteger nanos) - { - Interval interval = new Interval("P0Y"); - interval.Months = months; - interval.Days = days; - interval.Nanoseconds = nanos; - - return interval; - } + public static Interval FromDays(int days) => new Interval(0, days, 0); /// - /// Creates an interval based on the Months given + /// Creates an Interval based on the seconds given. /// - public static Interval OfMonths(int months) - { - return new Interval($"P{months}M"); - } + public static Interval FromSeconds(BigInteger seconds) => new Interval(0, 0, NanosecondsInASecond * seconds); /// - /// Creates an Interval based on the Days given + /// Creates an Interval based on the milliseconds given. /// - public static Interval OfDays(int days) - { - return new Interval($"P{days}D"); - } + public static Interval FromMilliseconds(BigInteger milliseconds) => new Interval(0, 0 , NanosecondsInAMillisecond * milliseconds); /// - /// Creates an Interval based on the seconds given + /// Creates an Interval based on the microseconds given. /// - public static Interval ofSeconds(int seconds) - { - return new Interval($"PT{seconds}S"); - } + public static Interval FromMicroseconds(BigInteger microseconds) => new Interval(0, 0, NanosecondsInAMicrosecond * microseconds); /// - /// Creates an Interval based on the milliseconds given + /// Creates an Interval based on the nanoseconds given. /// - public static Interval ofMilliseconds(long milliseconds) - { - return new Interval($"PT{(decimal) milliseconds / 1000}S"); - } - - /// - /// Creates an Interval based on the microseconds given - /// - public static Interval ofMicroseconds(long microseconds) - { - return new Interval($"PT{(decimal) microseconds / 1000000}S"); - } - - /// - /// Creates an Interval based on the nanoseconds given - /// - public static Interval ofNanoseconds(ulong nanoseconds) - { - return new Interval($"PT{(decimal) nanoseconds / 1000000000}S"); - } + public static Interval FromNanoseconds(BigInteger nanoseconds) => new Interval(0, 0, nanoseconds); - private int YearsToMonths(string years) - { - return int.Parse(years) * 12; - } + private static int YearsToMonths(string years) => int.Parse(years) * 12; - private BigInteger HoursToNanoseconds(string hours) - { - return BigInteger.Parse(hours) * NanosecondsInAnHour; - } + private static BigInteger HoursToNanoseconds(string hours) => BigInteger.Parse(hours) * NanosecondsInAnHour; - private BigInteger MinutesToNanoseconds(string minutes) - { - return BigInteger.Parse(minutes) * NanosecondsInAMinute; - } + private static BigInteger MinutesToNanoseconds(string minutes) => BigInteger.Parse(minutes) * NanosecondsInAMinute; - private BigInteger SecondsToNanoseconds(string seconds) + private static BigInteger SecondsToNanoseconds(string seconds) { string[] splitNumber = seconds.Split('.'); - if (splitNumber.Length > 2) { + if (splitNumber.Length > 2) + { throw new FormatException("Invalid Format"); } @@ -315,7 +244,8 @@ private BigInteger SecondsToNanoseconds(string seconds) private bool validateInt(string number) { - if (number.Contains('.')) { + if (number.Contains('.')) + { return false; } From 41b02ea6d913e466d2a49e22346fd9931d54cb15 Mon Sep 17 00:00:00 2001 From: Hector Mendoza Jacobo Date: Thu, 20 Feb 2025 18:57:35 -0500 Subject: [PATCH 3/3] Change comments format --- .../Google.Cloud.Spanner.V1/Interval.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apis/Google.Cloud.Spanner.V1/Google.Cloud.Spanner.V1/Interval.cs b/apis/Google.Cloud.Spanner.V1/Google.Cloud.Spanner.V1/Interval.cs index ed8453bf3a84..18525a1d9199 100644 --- a/apis/Google.Cloud.Spanner.V1/Google.Cloud.Spanner.V1/Interval.cs +++ b/apis/Google.Cloud.Spanner.V1/Google.Cloud.Spanner.V1/Interval.cs @@ -21,7 +21,7 @@ namespace Google.Cloud.Spanner.V1 { /// - /// Representation of a Time Interval + /// Representation of a Time Interval. /// public class Interval { @@ -38,22 +38,22 @@ public class Interval internal const long NanosecondsInAMicrosecond = 1000L; /// - /// Months contained in the interval + /// Months contained in the interval. /// public int Months { get; set; } = 0; /// - /// Days contained in the interval + /// Days contained in the interval. /// public int Days { get; set; } = 0; /// - /// Nanoseconds contained in the interval + /// Nanoseconds contained in the interval. /// public BigInteger Nanoseconds { get; set; } = 0; /// - /// Representation of a Time Interval + /// Representation of a Time Interval. /// private Interval(int months, int days, BigInteger nanoseconds) { @@ -63,7 +63,7 @@ private Interval(int months, int days, BigInteger nanoseconds) } /// - /// Constructs + /// Constructs an interval based on an Iso8601 duration string. /// public static Interval FromIso8601String(string intervalString) {