Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
20 changes: 20 additions & 0 deletions src/OneScript.StandardLibrary/Json/GlobalJsonFunctions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,26 @@ public IValue ReadJSONDate(string String, JSONDateFormatEnum? format)
}
}

/// <summary>
/// Преобразовывает дату в строку для последующей записи в формат JSON.
/// </summary>
///
/// <param name="dateValue">
/// Дата, которую надо преобразовать в формат JSON. </param>
/// <param name="format">
/// Формат записываемой даты. </param>
/// <param name="dateWritingVariant">
/// Вариант записи даты JSON. Значение по умолчанию: ЛокальнаяДата. </param>
///
/// <returns name="String">
/// Значения данного типа содержат строку в формате Unicode произвольной длины.</returns>
///
[ContextMethod("ЗаписатьДатуJSON", "WriteJSONDate")]
public string WriteJSONDate(IValue dateValue, JSONDateFormatEnum format, JSONDateWritingVariantEnum dateWritingVariant = JSONDateWritingVariantEnum.LocalDate)
{
return JSONDateWriter.Write(dateValue, format, dateWritingVariant);
}

/// <summary>
///
/// Выполняет сериализацию Значение в формат JSON. Результат помещает в объект ЗаписьJSON.
Expand Down
143 changes: 143 additions & 0 deletions src/OneScript.StandardLibrary/Json/JSONDateWriter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
/*----------------------------------------------------------
This Source Code Form is subject to the terms of the
Mozilla Public License, v.2.0. If a copy of the MPL
was not distributed with this file, You can obtain one
at http://mozilla.org/MPL/2.0/.
----------------------------------------------------------*/

using System;
using System.Globalization;
using OneScript.Commons;
using OneScript.Exceptions;
using OneScript.Types;
using ScriptEngine.Machine;

namespace OneScript.StandardLibrary.Json
{
internal static class JSONDateWriter
{
public static string Write(IValue dateValue, JSONDateFormatEnum format, JSONDateWritingVariantEnum dateWritingVariant)
{
var date = GetDateArgument(dateValue);
date = DropSubsecond(date);

switch (format)
{
case JSONDateFormatEnum.ISO:
return WriteISODate(date, dateWritingVariant);

case JSONDateFormatEnum.JavaScript:
CheckUniversalDateWritingVariant(format, dateWritingVariant);
return $"new Date({UnixMilliseconds(ConvertLocalTimeToUtc(date))})";

case JSONDateFormatEnum.Microsoft:
CheckUniversalDateWritingVariant(format, dateWritingVariant);
return $"/Date({UnixMilliseconds(ConvertLocalTimeToUtc(date))})/";

default:
throw RuntimeException.InvalidNthArgumentValue(2);
}
}

private static DateTime GetDateArgument(IValue dateValue)
{
if (dateValue?.SystemType != BasicTypes.Date)
{
throw RuntimeException.InvalidNthArgumentType(1);
}

return dateValue.AsDate();
}

private static string WriteISODate(DateTime date, JSONDateWritingVariantEnum dateWritingVariant)
{
switch (dateWritingVariant)
{
case JSONDateWritingVariantEnum.LocalDate:
return FormatISODate(date);

case JSONDateWritingVariantEnum.LocalDateWithOffset:
return FormatISODate(date) + FormatJSONDateOffset(GetLocalUtcOffset(date));

case JSONDateWritingVariantEnum.UniversalDate:
return FormatISODate(ConvertLocalTimeToUtc(date)) + "Z";

default:
throw RuntimeException.InvalidNthArgumentValue(3);
}
}

private static string FormatISODate(DateTime date)
{
return date.ToString("yyyy-MM-dd'T'HH:mm:ss", CultureInfo.InvariantCulture);
}

private static DateTime ConvertLocalTimeToUtc(DateTime date)
{
if (date == DateTime.MinValue)
{
return DateTime.MinValue;
}

return TimeZoneInfo.ConvertTimeToUtc(AsUnspecified(date), TimeZoneInfo.Local);
}

private static TimeSpan GetLocalUtcOffset(DateTime date)
{
if (date == DateTime.MinValue)
{
return TimeSpan.Zero;
}

return TimeZoneInfo.Local.GetUtcOffset(AsUnspecified(date));
}

private static DateTime AsUnspecified(DateTime date)
{
return DateTime.SpecifyKind(date, DateTimeKind.Unspecified);
}

private static DateTime DropSubsecond(DateTime date)
{
return new DateTime(date.Year, date.Month, date.Day, date.Hour, date.Minute, date.Second);
}

private static long UnixMilliseconds(DateTime utcDate)
{
var utc = DateTime.SpecifyKind(utcDate, DateTimeKind.Utc);
return new DateTimeOffset(utc).ToUnixTimeMilliseconds();
}

private static string FormatJSONDateOffset(TimeSpan offset)
{
var sign = offset < TimeSpan.Zero ? "-" : "+";
var totalMinutes = Math.Abs((int)Math.Truncate(offset.TotalMinutes));
var hours = totalMinutes / 60;
var minutes = totalMinutes % 60;

return $"{sign}{hours:00}:{minutes:00}";
}

private static void CheckUniversalDateWritingVariant(JSONDateFormatEnum format, JSONDateWritingVariantEnum dateWritingVariant)
{
if (dateWritingVariant == JSONDateWritingVariantEnum.UniversalDate)
{
return;
}

if (format == JSONDateFormatEnum.JavaScript)
{
throw new RuntimeException(Locale.NStr(
"ru='Невозможно сохранить локальную дату в формате JavaScript'; en='Cannot save local date in JavaScript format'"));
}

if (format == JSONDateFormatEnum.Microsoft)
{
throw new RuntimeException(Locale.NStr(
"ru='Невозможно сохранить локальную дату в формате Microsoft'; en='Cannot save local date in Microsoft format'"));
}

throw RuntimeException.InvalidNthArgumentValue(2);
}
}
}
26 changes: 26 additions & 0 deletions src/OneScript.StandardLibrary/Json/JSONDateWritingVariantEnum.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*----------------------------------------------------------
This Source Code Form is subject to the terms of the
Mozilla Public License, v.2.0. If a copy of the MPL
was not distributed with this file, You can obtain one
at http://mozilla.org/MPL/2.0/.
----------------------------------------------------------*/

using OneScript.Contexts.Enums;

namespace OneScript.StandardLibrary.Json
{
[EnumerationType("ВариантЗаписиДатыJSON", "JSONDateWritingVariant",
TypeUUID = "7B1B8BE8-0EA9-47BF-BAAF-8BC6A4756E8B",
ValueTypeUUID = "4DD7E419-8D53-4F4C-A3A5-8F7436A07734")]
public enum JSONDateWritingVariantEnum
{
[EnumValue("ЛокальнаяДата", "LocalDate")]
LocalDate,

[EnumValue("ЛокальнаяДатаСоСмещением", "LocalDateWithOffset")]
LocalDateWithOffset,

[EnumValue("УниверсальнаяДата", "UniversalDate")]
UniversalDate
}
}
Loading