Рассмотрим следующий голанг
today := time.Now().Format("2006-01-02T03:04:05.9999999Z")
t, _ := time.Parse(time.RFC3339Nano, today)
Почему это не эквивалентно гораздо более простому
t := time.Now()
?
Я хотел бы подтвердить, является ли приведенный выше код эквивалентным, как я считаю, или почему это не так, исходя из моего текущего опыта. Я также предоставляю дополнительный контекст относительно того, что я пытался.
Мой полный код репозитория здесь, на GitHub в файле main.go. Однако для ответа на этот вопрос давайте сосредоточимся на фрагменте кода, представленном ниже.
sasToken, err := client.ListAccountSAS(
ctx, resourceGroupName, storageAccountName, armstorage.AccountSasParameters{
KeyToSign: to.Ptr("key1"),
SharedAccessExpiryTime: to.Ptr(func() time.Time {
t, _ := time.Parse(time.RFC3339Nano, tomorrow); return t }()),
Permissions: to.Ptr(armstorage.PermissionsR),
Protocols: to.Ptr(armstorage.HTTPProtocolHTTPSHTTP),
ResourceTypes: to.Ptr(armstorage.SignedResourceTypesS),
Services: to.Ptr(armstorage.ServicesB),
SharedAccessStartTime: to.Ptr(func() time.Time {
t, _ := time.Parse(time.RFC3339Nano, today); return t }()),
}, nil)
В настоящее время этот код работает как положено. Однако , когда я упрощаю последнюю строку до t := time.Now(), это приводит к ошибке (показано в Выполнить задание в Github Actions).
today 2023-09-18T07:54:42.6314723Z should be formatted as 2023-09-16T11:42:03.1567373Z
tomorrow 2023-09-19T07:54:42.6314723Z should be formattes as 2023-09-17T11:42:03.1567373Z
2023/09/18 07:54:43 POST https://management.azure.com/subscriptions/***/resourceGroups/go-azure-sdk/providers/Microsoft.Storage/storageAccounts/golangazure/ListAccountSas
--------------------------------------------------------------------------------
RESPONSE 400: 400 Bad Request
ERROR CODE: InvalidValuesForRequestParameters
--------------------------------------------------------------------------------
{
"error": {
"code": "InvalidValuesForRequestParameters",
"message": "Values for request parameters are invalid: signedStart."
}
}
--------------------------------------------------------------------------------
exit status 1
Это заставило меня задаться вопросом, почему эквивалентность не имеет места, вопреки моим первоначальным ожиданиям.
@derpirscher Спасибо! Дайте мне несколько минут, я внесу изменения в код github, чтобы мы могли увидеть ошибку в журнале действий github (и я также обновлю вопрос)


Этот API ожидает, что время будет округлено до секунды. Итак, попробуйте что-то вроде:
...
SharedAccessExpiryTime: to.Ptr(expiryTime.Round(time.Second)),
...
SharedAccessStartTime: to.Ptr(startTime.Round(time.Second)),
...
Да, проверено, я подтверждаю, что это работает, спасибо, но, прежде чем принять это, пожалуйста, я все еще не понимаю, почему мой исходный код работал без округления до секунды и почему эта эквивалентность не соблюдается.
какую версию API вы используете? возможно, это проблема со старым API. Рассмотрим последнюю версию кода от 01.01.2023, обратитесь к примеру кода, который вы вставили Learn.microsoft.com/en-us/rest/api/storagerp/storage-accounts/…
мой go.mod здесь github.com/giuliohome-org/go-azure/blob/main/go.mod
если вы проверите из пользовательского интерфейса, максимальная точность, которую вы можете установить, равна second
конечно, я уже исправил код по вашему предложению, я просто хочу понять, что происходит с точки зрения Голанга, прежде чем закрыть эту тему. (кстати, последнее UTC() не имеет значения)
Теперь я понимаю, что с точки зрения кода Голанга основная проблема сводится к концепции монотонного чтения часов:
Время возвращается по времени. Теперь содержит монотонное показание часов.
Включение монотонного показания часов — это то, что может вызвать проблемы в определенных сценариях, возможно, из-за некоторой внутренней интерпретации параметра. Однако при использовании функции time.Parse такого монотонного показания часов нет.
Стоит отметить, что, поскольку монотонное чтение часов не имеет смысла вне текущего процесса, различные функции и методы в пакете Go time обрабатывают его по-разному. Такие функции, как t.Round(d), удаляют монотонные показания часов из их результатов. Именно из-за такого поведения принятый ответ работает, поскольку он использует такие функции для достижения желаемого результата.
Редактировать
Я также определил, где, скорее всего, заключается проблема в исходном коде SDK. Проблема заключается в форматах времени, используемых SDK, а именно:
var timeFormats = []string{
"2006-01-02T15:04:05.0000000Z",
TimeFormat,
"2006-01-02T15:04Z",
"2006-01-02",
}
Важнейшей деталью здесь является то, что первый формат времени содержит только 7 десятичных знаков. Это объясняет, почему мне пришлось использовать Format("2006-01-02T03:04:05.9999999Z") вместо более простого Format(time.RFC3339Nano).
В их документации о политике доступа указаны принятые форматы ISO 8601 UTC. В нем упоминается:
Если значение времени включает секунды, оно также может дополнительно включать до 7 десятичных цифр дробных секунд по шаблону чч:мм:сс[.f{1,7}]. Этот шаблон поддерживается API-интерфейсами хранилища Azure, инструментами и клиентскими библиотеками.
Следовательно, Round(time.Microsecond) по-прежнему будет работать, но попытка округления с помощью Round(time.Nanosecond) потерпит неудачу.
хороший улов @Джулио!!!!
@Matteo еще раз спасибо за помощь и решение. Собственно, это и имеет смысл сделать.
Какая у вас ошибка?