Skip to content
Draft
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
247386a
Adding product line based population in the dictionary as the Annotat…
igajurelNCQA Sep 3, 2025
2b4b555
FIxed bug - when date is assigned as Maz/Min value, Quantity add/subt…
igajurelNCQA Sep 4, 2025
73a0e74
Fix Bug - Slice operation fixed to follow Slice semantics used by htt…
igajurelNCQA Sep 4, 2025
9783b97
unit tests for Slice fixes
igajurelNCQA Sep 5, 2025
282d5a6
Fixed Units normalization - A datetime quantity unit can be ucum or c…
igajurelNCQA Sep 5, 2025
35e6535
just retain unit normalization based changes
igajurelNCQA Sep 10, 2025
ef21f0e
Merge branch 'develop' into Unit-normalization-fixes-for-UCUM-and-Cal…
igajurelNCQA Sep 10, 2025
4aab83d
xml fix
igajurelNCQA Sep 13, 2025
344b344
Merge branch 'develop' into Unit-normalization-fixes-for-UCUM-and-Cal…
igajurelNCQA Sep 13, 2025
d6466ae
Merge branch 'develop' into Unit-normalization-fixes-for-UCUM-and-Cal…
igajurelNCQA Sep 17, 2025
24cd09d
resolve issues with public API shipped constructs
igajurelNCQA Sep 17, 2025
d1c3a15
Merge branch 'develop' into Unit-normalization-fixes-for-UCUM-and-Cal…
igajurelNCQA Sep 18, 2025
915f64d
Merge branch 'develop' into Unit-normalization-fixes-for-UCUM-and-Cal…
igajurelNCQA Sep 19, 2025
651e655
address copilot comments
igajurelNCQA Sep 19, 2025
55a203e
Update Cql/Cql.Abstractions/Abstractions/UCUMUnits.cs
igajurelNCQA Sep 19, 2025
7a8bdc1
address copilot comment
igajurelNCQA Sep 19, 2025
6c9d8ff
Merge branch 'Unit-normalization-fixes-for-UCUM-and-Calendar-based-Cq…
igajurelNCQA Sep 19, 2025
ea583bc
address copilot comment
igajurelNCQA Sep 19, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Cql/CoreTests/ModelTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public void Age()
var ctx = new CqlContext(CqlOperators.Create(new UnitTestTypeResolver(),
dataSource: dataSource,
now: new DateTimeIso8601(2023, 3, 28, null, null, null, null, null, null)));
var age = ctx.Operators.Age("a");
var age = ctx.Operators.Age("year");
Assert.AreEqual(age, 39);
}

Expand All @@ -51,7 +51,7 @@ public void AgeAt()
var ctx = new CqlContext(CqlOperators.Create(new UnitTestTypeResolver(),
dataSource: dataSource,
now: new DateTimeIso8601(2023, 3, 28, null, null, null, null, null, null)));
var age = ctx.Operators.AgeAt(new CqlDate(2013, 3, 28), "a");
var age = ctx.Operators.AgeAt(new CqlDate(2013, 3, 28), "year");
Assert.AreEqual(age, 29);
}

Expand Down
45 changes: 36 additions & 9 deletions Cql/CoreTests/PrimitiveTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ public class PrimitiveTests
public void CqlDate_Subtract_Months_From_Year()
{
Assert.IsTrue(CqlDateTime.TryParse("2014", out var baseDate));
var result = baseDate.Subtract(new CqlQuantity(25m, UCUMUnits.Month));
Assert.AreEqual(2012, result.Value.Year);
var result = baseDate.Subtract(new CqlQuantity(25m, "month"));
Assert.AreEqual(2011, result.Value.Year);
Assert.AreEqual(DateTimePrecision.Year, result.Precision);
}

Expand All @@ -54,7 +54,7 @@ public void CqlDateTime_Add_Year_By_Units()
var plus365days = baseDate.Add(new CqlQuantity(365, "day"));
Assert.AreEqual(DateTimePrecision.Year, plus365days.Value.Precision);
Assert.IsNull(plus365days.Value.Month);
Assert.AreEqual("1961", plus365days.ToString());
Assert.AreEqual("1960", plus365days.ToString());

var plus366days = baseDate.Add(new CqlQuantity(366, "day"));
Assert.AreEqual(DateTimePrecision.Year, plus366days.Value.Precision);
Expand All @@ -69,7 +69,7 @@ public void CqlDateTime_Add_Year_By_Units()
var plus365DaysInSeconds = baseDate.Add(new CqlQuantity(365 * 24 * 60 * 60, "seconds"));
Assert.AreEqual(DateTimePrecision.Year, plus365DaysInSeconds.Value.Precision);
Assert.IsNull(plus365DaysInSeconds.Value.Month);
Assert.AreEqual("1961", plus365DaysInSeconds.ToString());
Assert.AreEqual("1960", plus365DaysInSeconds.ToString());
}

[TestMethod]
Expand All @@ -92,6 +92,11 @@ public void CqlDateTime_Add_Month()
Assert.IsNull(plus2pt5Months.Value.Hour);
Assert.AreEqual("2022-03-01", plus2pt5Months.ToString());

var plus1UcumMonth = baseDate.Add(new CqlQuantity(1m, "mo"));
Assert.AreEqual(DateTimePrecision.Day, plus1UcumMonth.Value.Precision);
Assert.IsNull(plus1UcumMonth.Value.Hour);
Assert.AreEqual("2022-01-31", plus1UcumMonth.ToString());

}

[TestMethod]
Expand All @@ -114,6 +119,28 @@ public void CqlDateTime_Subtract_Month()
Assert.IsNull(minus2pt5Months.Value.Hour);
Assert.AreEqual("2022-01-01", minus2pt5Months.ToString());

var minus1UcumMonth = baseDate.Subtract(new CqlQuantity(1m, "mo"));
Assert.AreEqual(DateTimePrecision.Day, minus1UcumMonth.Value.Precision);
Assert.IsNull(minus1UcumMonth.Value.Hour);
Assert.AreEqual("2022-01-29", minus1UcumMonth.ToString());

}

[TestMethod]
public void CqlDateTime_Subtract_Year()
{
Assert.IsTrue(CqlDateTime.TryParse("2025-03-01", out var baseDate));

var minus1Year = baseDate.Subtract(new CqlQuantity(1m, "year"));
Assert.AreEqual(DateTimePrecision.Day, minus1Year.Value.Precision);
Assert.IsNull(minus1Year.Value.Hour);
Assert.AreEqual("2024-03-01", minus1Year.ToString());

var minus1UcumYear = baseDate.Subtract(new CqlQuantity(1m, "a"));
Assert.AreEqual(DateTimePrecision.Day, minus1UcumYear.Value.Precision);
Assert.IsNull(minus1UcumYear.Value.Hour);
Assert.AreEqual("2024-02-29", minus1UcumYear.ToString());

}

[TestMethod]
Expand Down Expand Up @@ -1075,7 +1102,7 @@ public void Expand_Interval_DateTime_Second()
var end = new CqlDateTime(2022, 1, 1, 0, 0, 6, 0, 0, 0);

var interval = new CqlInterval<CqlDateTime>(start, end, true, true);
var quantity = new CqlQuantity(3, "secondd");
var quantity = new CqlQuantity(3, "second");
List<CqlDateTime> expected =
[
new CqlDateTime(2022, 1, 1, 0, 0, 0, 0, 0, 0),
Expand Down Expand Up @@ -1216,11 +1243,11 @@ public void Expand_Interval_Time_Year()
var end = new CqlTime(12, null, null, null, null, null);

var interval = new CqlInterval<CqlTime>(start, end, true, true);
var quantity = new CqlQuantity(2, "years");
var perQuantity = new CqlQuantity(2, "year");

var rc = GetNewContext(); var fcq = rc.Operators;

var expand = fcq.Expand(interval, quantity);
var expand = fcq.Expand(interval, perQuantity);
Assert.IsNotNull(expand);
Assert.IsTrue(expand.Count() == 0);
}
Expand Down Expand Up @@ -2985,11 +3012,11 @@ public void Expand_List_Interval_Time_Year()
var end = new CqlTime(12, null, null, null, null, null);

List<CqlInterval<CqlTime>> interval = [new CqlInterval<CqlTime>(start, end, true, true)];
var quantity = new CqlQuantity(2, "years");
var perQuantity = new CqlQuantity(2, "year");

var rc = GetNewContext(); var fcq = rc.Operators;

var expand = fcq.Expand(interval, quantity);
var expand = fcq.Expand(interval, perQuantity);
Assert.IsNotNull(expand);
Assert.IsTrue(expand.Count() == 0);
}
Expand Down
27 changes: 10 additions & 17 deletions Cql/Cql.Abstractions/Abstractions/UCUMUnits.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,26 +79,19 @@ public static class UCUMUnits
/// Centimeters
/// </summary>
public const string Centimeter = "cm";

/// <summary>
/// Maps <see cref="DateTimePrecision"/> to the corresponding UCUM unit.
/// List of UCUM units commonly used for date and time intervals.
/// Defines days per year
/// </summary>
/// <param name="dtp">The precision to map.</param>
/// <returns>The corresponding UCUM units, or <see langword="null"/> if no mapping is defined.</returns>
public static string? FromDateTimePrecision(DateTimePrecision dtp)
public static readonly HashSet<string> DateTimeUnits = new HashSet<string>
{
return dtp switch
{
DateTimePrecision.Year => Year,
DateTimePrecision.Month => Month,
DateTimePrecision.Day => Day,
DateTimePrecision.Hour => Hour,
DateTimePrecision.Minute => Minute,
DateTimePrecision.Second => Second,
DateTimePrecision.Millisecond => Millisecond,
_ => null,
};
}
Year, Month, Day, Hour, Minute, Second, Millisecond
};
public const double DaysPerYearDouble = 365.25d;
/// <summary>
/// Defines days per month
/// </summary>
public const double DaysPerMonthDouble = 30.4375d;
}


Expand Down
46 changes: 11 additions & 35 deletions Cql/Cql.Abstractions/Abstractions/Units.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,47 +9,23 @@
namespace Hl7.Cql.Abstractions
{
/// <summary>
/// Utilities for converting between CQL and UCUM units.
/// Utilities for converting precision to cql units
/// </summary>
public static class Units
{
/// <summary>
/// Maps CQL unit keywords (singular or plural) to their corresponding UCUM unit codes.
/// Maps DateTime Precisions to their corresponding CQL units.
/// </summary>
/// <see href="https://www.hl7.org/fhir/valueset-ucum-units.html"/>
public static readonly IDictionary<string, string> CqlUnitsToUCUM = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
public static readonly IDictionary<string, string> DatePrecisionToCqlUnits = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{
{ "year", UCUMUnits.Year },
{ "years", UCUMUnits.Year },
{ "month", UCUMUnits.Month },
{ "months", UCUMUnits.Month },
{ "days", UCUMUnits.Day },
{ "day", UCUMUnits.Day },
{ "week", UCUMUnits.Week },
{ "weeks", UCUMUnits.Week },
{ "hour", UCUMUnits.Hour },
{ "hours", UCUMUnits.Hour },
{ "minute", UCUMUnits.Minute },
{ "minutes", UCUMUnits.Minute },
{ "second", UCUMUnits.Second },
{ "seconds", UCUMUnits.Second },
{ "millisecond", UCUMUnits.Millisecond },
{ "milliseconds", UCUMUnits.Millisecond },
};

/// <summary>
/// Maps UCUM unit codes to their corresponding CQL keywords, singular.
/// </summary>
public static readonly IDictionary<string, string> UCUMUnitsToCql = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{
{ UCUMUnits.Year, "year" },
{ UCUMUnits.Month, "month" },
{ UCUMUnits.Week, "week" },
{ UCUMUnits.Day, "day" },
{ UCUMUnits.Hour, "hour" },
{ UCUMUnits.Minute, "minute" },
{ UCUMUnits.Second, "second" },
{ UCUMUnits.Millisecond, "millisecond" },
{ "Year", "year" },
{ "Month", "month" },
{ "Day", "day" },
{ "Week", "week" },
{ "Hour", "hour" },
{ "Minute", "minute" },
{ "Second", "second" },
{ "Millisecond", "millisecond" }
};

}
Expand Down
Loading
Loading