Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add -AsLocal switch to Get-Date #11731

Closed
scotthardwick opened this issue Jan 30, 2020 · 24 comments
Closed

Add -AsLocal switch to Get-Date #11731

scotthardwick opened this issue Jan 30, 2020 · 24 comments
Labels
Issue-Enhancement the issue is more of a feature request than a bug Resolution-No Activity Issue has had no activity for 6 months or more WG-Cmdlets-Utility cmdlets in the Microsoft.PowerShell.Utility module

Comments

@scotthardwick
Copy link

Similar to the recent PR that added the -AsUTC switch to Get-Date, we should also have the ability to set Local DateTimeKind as well.

Examples of how this would work:

Get-Date "1/12/2020 4:00pm" -Format "MM/dd/yyyy HH:mm K"
# The DateTimeKind here is Unspecified, so result is 01/12/2020 16:00

Get-Date ((Get-Date "1/12/2020 4:00pm").ToUniversalTime()) -Format "MM/dd/yyyy HH:mm K"
Get-Date "1/12/2020 4:00pm" -AsUTC -Format "MM/dd/yyyy HH:mm K"
# The DateTimeKind here is Utc, so result is 01/12/2020 22:00 Z

Get-Date ((Get-Date "1/12/2020 4:00pm").ToLocalTime()) -Format "MM/dd/yyyy HH:mm K"
Get-Date "1/12/2020 4:00pm" -AsLocal -Format "MM/dd/yyyy HH:mm K"
# The DateTimeKind here is Local, so result is 01/12/2020 10:00 -06:00
@scotthardwick scotthardwick added the Issue-Enhancement the issue is more of a feature request than a bug label Jan 30, 2020
@mklement0
Copy link
Contributor

Great idea.
For the sake of completeness, -AsUnspecified would be helpful too, if you're expressly looking for an abstract point in time.

I assume the intent of the -As* switches is to either directly output a [datetime] instance with the indicated .Kind value (UTC, Local, Unspecified), or to make such an instance the basis for applying the -Format / -UFormat format.

We have to be careful about the logic of interpreting the input, however:

From what I can tell, only Get-Date -Date with either a string argument (except strings explicitly indicating UTC or containing a time-zone offset) or a [datetime] instance whose .Kind is Unspecified currently results in the output [datetime] instance having .Kind Unspecified; otherwise, it is Local (or will be Utc with -AsUtc).

The tricky part is that Unspecified instances are treated situationally either as representing UTC or as representing LOCAL time:

  • .ToUniversalTime() interprets an Unspecified instance as Local
  • .ToLocalTime() interprets an Unspecified instance as Utc(!)

Therefore, as also implied by your last example command:

# NOTE: Interprets the given date *as UTC*
PS> (Get-Date "1/12/2020 4:00pm").ToLocalTime()

Sunday, January 12, 2020 11:00:00 AM   # e.g., in the US Eastern time zone

This is .NET's behavior, over which we have no control, but I wonder if surfacing this behavior via
-AsLocal would cause confusion:

# !! If we just call .ToLocalTime() behind the scenes, we get the same behavior as above:
# !! The given date is interpreted *as UTC* and then *converted to a local date*.
Get-Date "1/12/2020 4:00pm" -AsLocal

My expectation would be that the nominal date given (in text form) would be interpreted as-is as a local date; which is the equivalent of:

PS> [datetime]::new((Get-Date "1/12/2020 4:00pm").Ticks, 'Local') | Select DateTime, Kind

DateTime                             Kind
--------                             ----
Sunday, January 12, 2020 4:00:00 PM Local

Note how the unspecified input date string was now interpreted as a local time, as reflected in the output [datetime] instance, which has .Kind Local, as requested.

@iSazonov iSazonov added the WG-Cmdlets-Utility cmdlets in the Microsoft.PowerShell.Utility module label Jan 31, 2020
@SeeminglyScience
Copy link
Collaborator

+1 @mklement0. I would expect it to use:

[datetime]::Parse(
    '4pm',
    [cultureinfo]::CurrentCulture,
    [Globalization.DateTimeStyles]::AssumeLocal)

@mklement0
Copy link
Contributor

Thanks, @SeeminglyScience, but note that since the -Date parameter is [datetime]-typed, I think it is the parameter binder that performs the parsing up front (culture-sensitively, due to being a cmdlet argument, as opposed to the culture-invariant parsing that happens with casts or advanced functions, which is a won't-fix inconsistency; see #6989)

Therefore, I think Get-Date already sees the parsed result, which is a [datetime] instance with a .Kind value of Unspecified - hence my suggestion to use [datetime]::new(<ticks>, <kind>).

@scotthardwick
Copy link
Author

@mklement0 and @SeeminglyScience Thanks for joining in!

If we are including all three DateTimeKind options, do you think we need a parameter more like
-AsDateTimeKind Utc
-AsDateTimeKind Local
-AsDateTimeKind Unspecified
?

-AsUTC hasn't been part of a formal release yet, so now would be the time to change it if the PowerShell team was going to?

@mklement0
Copy link
Contributor

I'd say, given that there's only 3 enumeration values whose number is unlikely to grow, it's easier on users to use distinct switches, -AsUtc, -AsLocal, -AsUnspecified.

@scotthardwick
Copy link
Author

@mklement0 Fair point. I can accept that ;-)

@mklement0
Copy link
Contributor

Then again, for invocation with programmatically constructed parameters something like -AsKind Utc|Local|Unspecified is preferable...

Having our cake and eating it too (providing -AsUtc as an effective alias of -AsKind Utc, ...) is also an option, but might get confusing / be a pain to implement (many parameter sets).

@scotthardwick
Copy link
Author

;-) I have only started posting suggestions for PowerShell in the last few days and I hate to ask for the moon, so I am trying to be semi-conservative in my asks. I will take it either way ;-)

@ThomasNieto
Copy link
Contributor

Since we're adding multiple options here for the kind it should be an enum not switch parameter. Right now if we add -AsUtc and -AsLocal and -AsUnspecified those three switch parameters will need to be in separate parameter sets since you can't have multiple passed at the same time.

@mklement0
Copy link
Contributor

mklement0 commented Feb 4, 2020

As stated before, for programmatic construction of arguments -AsKind <kind> is preferable; that doesn't necessary preclude also providing convenience aliases (-AsUtc for -AsKind Utc, ...; they wouldn't be the first of their kind), but I get that this (a) could be a paint to implement (proliferation of parameter sets) and (b) the duplication could cause conceptual confusion.

In short: I'm personally fine with only implementing -AsKind <kind>, if that's the consensus.

However, we should then act quickly, before 7.0 GA ships with the recently implemented -AsUtc switch.

@ThomasNieto
Copy link
Contributor

Do you have any examples of a alias switch parameter mapping to another parameter?

@mklement0
Copy link
Contributor

The one that readily comes to mind is Get-Location -Stack for Get-Location -StackName '', but, if memory serves, there are more; they're not easy to search for.

@mklement0
Copy link
Contributor

mklement0 commented Feb 6, 2020

More relatable examples:

  • In Get-ChildItem: -Directory / for Attributes -Directory, -File for -Attributes !Directory, -Hidden for -Attributes Hidden, -ReadOnly for -Attributes ReadOnly, -System for Attributes System.

  • In Import-Module: -Global for -Scope Global ("The Global parameter is equivalent to the Scope parameter with a value of Global." - help).

I'm curious, though, @ThomasNieto: Are you asking not just because you were curious / weren't convinced that there is such a thing, or are you philosophically opposed to the concept?

@ThomasNieto
Copy link
Contributor

@mklement0 I was unaware of them or had used them without knowing. The concern I have with them is that you can get into scenarios like this where you can pass conflicting parameters. Normally tab completion will prevent a user from passing parameters that cannot be used together. In the first example -Global and -Scope can't be used together but is allowed by tab completion since they're in the same parameter set. The second example is where both can be used at the same time if all attributes are met.

To sum it up, I think convenience parameters have a place where they can be used in conjunction with the other parameter. PowerShell has done a good job with parameter sets protecting the user from passing parameters that cannot be used together through tab completion and help.

C:\> Import-Module AssignedAccess -Global -Scope Local
Import-Module: The 'Global' and 'Scope' parameters cannot be specified together. Remove one of these parameters, and then try running the command again.
C:\> Get-ChildItem -Attributes Directory -Hidden


    Directory: C:\

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d--hs           12/4/2019 10:42 PM                $Recycle.Bin
l--hs           12/4/2019 11:35 PM                Documents and Settings -> C:\Users
d--h-            2/3/2020 10:09 AM                ProgramData
d--hs           12/4/2019 11:35 PM                Recovery
d--hs            2/5/2020  6:09 PM                System Volume Information

@mklement0
Copy link
Contributor

mklement0 commented Feb 6, 2020

or had used them without knowing.

That's a testament to their usefulness.

To sum it up, I think convenience parameters have a place where they can be used in conjunction with the other parameter

While you can squeeze combinations out of -File/ -Directory, ... vs. -Attributes, it's awkward and potentially self-defeating:

# Allowed, but nonsensical
Get-ChildItem -File -Attributes directory

# The more intuitive way to write your example, using shortcut aliases only
Get-ChildItem -Directory -Hidden

The far more typical case is to use one or the other; if there's something you cannot model with combining the shortcut aliases alone, you're better off using just -Attributes.

With single-choice enumerations - as in the case of -Global vs. -Scope Global and in our case, -AsUtc, ... vs. -AsKind Utc - conceptual confusion doesn't even arise, because the shortcut aliases mustn't be combined with the verbose parameter.

As such, these single-choice scenarios strike me as the ideal use case for shortcut aliases.

That Import-Module currently implements this exclusion awkwardly is not an argument against the concept.

Similarly, the fact that implementing such mutual exclusion is currently cumbersome is not an argument - it just means that we need to make implementing this easier, as has been attempted before, in this since-withdrawn RFC: https://github.com/PowerShell/PowerShell-RFC/blob/master/X-Withdrawn/RFC0001-Mutual-Exclusion-Parameters-and-Properties.md

GitHub
RFC (Request for Comments) documents for community feedback on design changes and improvements to PowerShell ecosystem - PowerShell/PowerShell-RFC

@mklement0
Copy link
Contributor

To continue the discussion from #13084 (comment), where @iSazonov wrote:

I guess the DateTimeKind was added to mitigate Datetime type limitations (today we could use DateTimeOffset). I do not think that we should use DateTimeKind broadly.

Agreed that [datetimeoffset] is always the better choice, butGet-Date is currently a wrapper for [datetime] only and for reasons of backward compatibility it will have to remain that way, at least by default.

Therefore, it makes sense to support it more fully, and to also offer -AsLocal and -AsUnspecified / -AsKind <kind>.

A possible alternative is to eliminate the Unspecified kind from Get-Date as follows, in which case only implementing -AsUtc would be sufficient:

  • Unless -AsUtc is passed, always return a Local date.

This would mean that commands such as Get-Date 2020-1-1, which currently return an Unspecified date, would then return a Local date, which may be more in line with what users expect.

Technically, though, it is a breaking change.

@iSazonov
Copy link
Collaborator

iSazonov commented Jul 16, 2020

AsUTC was added in Preview only (#11611) and we can replace it with general parameter like -AsKind <kind> or -DateTimeKind <kind>. No needs exist for other parameters.

/cc @brendandburns

@aetos382
Copy link
Contributor

aetos382 commented Jul 24, 2020

I think it would be complete to take TimeZoneInfo (or its Id) instead of DateTimeKind (in which case the output would be DateTimeOffset).
As a special case of TimeZoneInfo, it supports UTC and Local.


For example, I may want to know what time '10:00 AM PDT' is in Japanese time (this format is often used as the start time for some event).
So, I think it would be useful if I could convert the time zone as follows.

Get-Date -Date '2020-07-25 10:00' -TimeZone PDT -AsTimeZone JST

But, time zone abbreviations such as 'PDT' and 'JST' are not specified in ISO 8601 and are not official.
Also, it is unclear whether 'JST' refers to 'Japan Standard Time' or 'Jerusalem Standard Time'.
Thus, I am not sure if we should accept these notations as arguments.

This command will accept the following formats.
But, if the command only accepts values in the following form, I don't think this specification is so useful.
Because before I can use the command, I have to find out the official name of the time zone or its offset.

Get-Date -Date '2020-07-25 10:00' -TimeZone 'America/Los_Angeles' -AsTimeZone 'Asia/Tokyo'
Get-Date -Date '2020-07-25 10:00' -Offset -7 -AsOffset +9

@aetos382
Copy link
Contributor

I think we should be cautious about using SwitchParameter and ParameterSetName together, as they don't work well together.
For example, not setting -AsUTC is equivalent to specifying -AsUTC:$false.
However, if -AsUTC and -AsLocal are mutually exclusive by parameter set, then if -AsUTC is not set, -AsLocal can be set, but if -AsUTC:$false is specified, -AsLocal cannot be set.

@vexx32
Copy link
Collaborator

vexx32 commented Jul 24, 2020

@aetos382 RE: parameter sets - yes, that's how it's designed, you're not supposed to be able to use them together. Switches supporting a -Switch:$false option doesn't change that, really, I don't think that allowing both for that reason is very clear or sensible. It's much clearer to show users via parameter sets (which are directly reflected in the syntax diagrams in the Get-Help output) which switches can and can't be used in tandem. It would be pointless and confusing to display a syntax diagram that seems to allow both, when in practice only one can be used.

As for the time zone suggestion, it would be best if you requested that in a new issue as it is an entirely separate request IMO.

Copy link
Contributor

This issue has not had any activity in 6 months, if this is a bug please try to reproduce on the latest version of PowerShell and reopen a new issue and reference this issue if this is still a blocker for you.

2 similar comments
Copy link
Contributor

This issue has not had any activity in 6 months, if this is a bug please try to reproduce on the latest version of PowerShell and reopen a new issue and reference this issue if this is still a blocker for you.

Copy link
Contributor

This issue has not had any activity in 6 months, if this is a bug please try to reproduce on the latest version of PowerShell and reopen a new issue and reference this issue if this is still a blocker for you.

@microsoft-github-policy-service microsoft-github-policy-service bot added the Resolution-No Activity Issue has had no activity for 6 months or more label Nov 16, 2023
@microsoft-github-policy-service microsoft-github-policy-service bot added Resolution-No Activity Issue has had no activity for 6 months or more labels Nov 16, 2023
Copy link
Contributor

This issue has been marked as "No Activity" as there has been no activity for 6 months. It has been closed for housekeeping purposes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Issue-Enhancement the issue is more of a feature request than a bug Resolution-No Activity Issue has had no activity for 6 months or more WG-Cmdlets-Utility cmdlets in the Microsoft.PowerShell.Utility module
Projects
None yet
Development

No branches or pull requests

7 participants