Retrieve datetime object in Powershell without the time portion - powershell

Is it possible to retrieve only the date portion of a datetime object in PowerShell? Reason being I need to compare the LastWriteTime property of files with today's date to determine whether to backup a file or not. As-is a datetime object includes the time as well which will always evaluate to false when I do something like:
if ($fileDate -eq $currentDate) {
# Do backup
}
I haven't found anyway to do this. If we use the format operator or a method, it converts the object to a string object. If you try to convert that back to a datetime object, it appends the time back onto the object. Probably something simple, but I've been looking at this script for a while and that's the last part that's breaking.

EDIT: As #jessehouwing points out in the comments below, my answers are unnecessarily complicated. Just use $datetime.Date.
A couple of ways to get a DateTime without any time component (ie set to midnight at the start of the date in question, 00:00:00):
$dateTime = <some DateTime>
$dateWithoutTime = $dateTime.AddSeconds(-$dateTime.Second).AddMinutes(-$dateTime.Minute).AddHours(-$dateTime.Hour)
or
$dateTime = <some DateTime>
$dateWithoutTime = Get-Date -Date ($dateTime.ToString("yyyy-MM-dd"))
I ran each version in a loop, iterating 100,000 times. The first version took 16.4 seconds, the second version took 26.5 seconds. So I would go with the first version, although it looks a little more complicated.
Based on answers found here: https://techibee.com/powershell/powershell-how-to-query-date-time-without-seconds/2737 (that article is about stripping just the seconds from a DateTime. But it can be extended to stripping hours, minutes and seconds).

Assuming $fileDate is not a dateTime object, then you can just convert both to strings and format them.
if ($fileDate.ToString() -eq $currentDate.ToString("dd/MM/yyyy")) {
# Do backup
}

This will not answer how to remove time on datetime, but to do your validation purpose of identifying when to backup.
I do suggest to subtract your two given date values and compare the result if total hours are already met to do your backup.
if (( $currentDate - $fileDate ).TotalDays > 7) {
# Do Backup
}
you can also validate for the following
Days :
Hours :
Minutes :
Seconds :
Milliseconds :
Ticks :
TotalDays :
TotalHours :
TotalMinutes :
TotalSeconds :
TotalMilliseconds :

Assuming $currentTime contains a DateTime object, you can retrieve a new DateTime object with the same date but with the time portion zeroed like this:
$midnight = Get-Date $currentTime -Hour 0 -Minute 0 -Second 0 -Millisecond 0

Related

Powershell cast string to time only

I have created a Powershell/XAML app, that on button press makes a RESTAPI call, parses the JSON response into fields in the app front end. All fine so far.
These fields will be populated with a string representing a time, so "1800" or "2000" etc.
The user can then change this from 1800 to 1900 for example.
This is all fine, and in the background the app will use 1900 to update a setting to be used in a POST back.
However there are other settings that are offset by 90 mins of the time above. I don't want the user to have update each one, which is why I am trying to programmatically.
But try as I might, I cannot take a string of 1800, add 90 mins to it and make the value 1930 (not 1890).
You could parse the input as a DateTime object (ignoring the date part) and then use the AddMinutes method.
$input = '1800'
$hour = $input.Substring(0,2)
$minute = $input.Substring(2,2)
$dateInputStr = "0001-01-01,${hour}:${minute}:00"
[datetime]$dateInput = ([datetime]$dateInputStr)
$dateInput = $dateInput.AddMinutes(90)
$dateInput.ToString("HHmm")
Using [timespan] instances is another option:
$time = '1800'
([timespan] ($time -replace '(?<=^..)', ':') + '01:30').ToString('hhmm') #->'1930'
$time -replace '(?<=^..)', ':' uses the regex-based -replace operator to insert : after the first two characters - see this regex101.com page for an explanation of the regex and the ability to experiment with it.
Due to expressing the results only in terms of hours and minutes, the calculation wraps around at midnight, so that adding '05:30', for instance, would yield '0030'
The RHS operand needn't be cast to [timespan] directly, because the data type of the LHS - with its explicit [timespan] cast - implicitly converts the RHS to [timespan] too, with '01:30' representing 1 hour and 30 minutes, i.e. 90 minutes.
If you want to define the duration to add in terms of 90 minutes, use the following instead (there are analogous static methods for other units, such as ::FromSeconds():
[timespan]::FromMinutes(90)
Alternatively, you can cast a number to [timespan], which is interpreted as ticks, which are 100-nanosecond units; there are 1e9 (10 to the power of 9) nanoseconds in a second, and therefore 1e7 100-nanosecond units in a second. Thus, multiplying with 1e7 gives you seconds, and multiplying that with 60 minutes.
# 90 minutes expressed as ticks
[timespan] 90 * (60 * 1e7)
When I read this question I wanted to solve it with minimal string manipulation, leaning on time related objects and methods instead. datetime was the first object I thought of, but it expects a date (year, month, day). Things actually simplify if we use timespan. Its static method, ParseExact, can parse the string directly.
$offsetTimeSpan = [timespan]::FromMinutes(90)
$timeField = '830'
$timeStr = $timeField.PadLeft(4, '0')
$timeSpan = [timespan]::ParseExact($timeStr, 'hhmm', [CultureInfo]::InvariantCulture)
$offsetTime = $timeSpan.Add($offsetTimeSpan)
$offsetTime.ToString('hhmm')
$timeField is used to represent the time you get from the RESTAPI. PadLeft is only needed if it's possible for a leading 0 to be missing. ParseExact does the heavy lifting of converting the string to a time type. Because timespan doesn't have an AddMinutes member, we use the Add method passing in a timespan of 90 minutes, $offsetTimeSpan.
You don't mention anything about overflowing past midnight. You can test for overflow using $offsetTime.Days, if any special processing is required.

Date conversion going wrong with different computer language

I wrote a Powershell script for billing of customers. I get the list of bills, detect the month and get that specific bill. The timestamps are in Unix format and somehow I mess something up in the conversion depending on system language.
For example:
$FirstDayPrevMonth = (get-date -Day 1 -Hour 0 -Minute 0 -second 0 -Millisecond 0).Addmonths(-1)
The conversion fails for systems that return: zondag 1 november 2020 00:00:00. The conversion succeeds for systems that return: Sunday, November 1, 2020 12:00:00 AM
The timestamp I get from the bills list is for example: 1604188800000
The I run the following function passing 1604188800000, which should return number of the month:
Function Convert-FromUnixDateToMonth ($UnixDate) {
(get-date( [timezone]::CurrentTimeZone.ToLocalTime(([datetime]'1/1/1970').Addmilliseconds($UnixDate)).ToString("MM/dd/yyyy") ) ) -as [int] ### -UFormat %m
}
The result for the english system is 11 (correct), for the Dutch system is 1 (incorrect). I know it is somewhere in the language setting but I just can't figure out how to change this so it would work independent of the language.
Try below function to convert a Unix timestamp to either Local or UTC DateTime object
function ConvertFrom-UnixTimeStamp([Int64]$UnixTimeStamp, [switch]$AsUTC) {
while ($UnixTimeStamp -lt -62135596800 -or $UnixTimeStamp -gt 253402300799) {
# Assume $UnixTimeStamp to include milli- or nano seconds
$UnixTimeStamp = [int64][math]::Truncate([double]$UnixTimeStamp / 1000)
}
if ($UnixTimeStamp -gt [Int32]::MaxValue) {
# see: https://en.wikipedia.org/wiki/Year_2038_problem
Write-Warning "The given value exceeds the [Int32]::MaxValue of 2147483647 and therefore enters the Year2038 Unix bug.."
}
# the Unix Epoch is January 1, 1970 midnight in UTC
# older PowerShell versions use:
# [DateTime]$epoch = New-Object System.DateTime 1970, 1, 1, 0, 0, 0, 0, Utc
[DateTime]$epoch = [DateTime]::new(1970, 1, 1, 0, 0, 0, 0, 'Utc')
$date = $epoch.AddSeconds($UnixTimeStamp)
if ($AsUTC) { $date } else { $date.ToLocalTime() }
# or use:
# if ($AsUTC) { [DateTimeOffset]::FromUnixTimeSeconds($UnixTimeStamp).UtcDateTime }
# else { [DateTimeOffset]::FromUnixTimeSeconds($UnixTimeStamp).LocalDateTime }
}
For your purposes, get the Month by using it like
(ConvertFrom-UnixTimeStamp 1604188800000).Month
Result on my Dutch system:
11
There is no reason to involve string representations of timestamps; apart from slowing things down, there's the pitfall of culture-specific interpretation, as you've experienced (see next section):
The simplest solution is to use type [datetimeoffset] (System.DateTimeOffset):
# Returns 11 - the month index - in all time zones *at or ahead of* UTC.
[datetimeoffset]::FromUnixTimeMilliseconds(1604188800000).LocalDateTime.Month
A corrected version of your solution attempt:
[timezone]::CurrentTimeZone.ToLocalTime(
([datetime] '1/1/1970').AddMilliSeconds(1604188800000)
).Month
Note that the from-string conversion from '1/1/1970' is unproblematic in this case, due to using a cast.
You didn't need a call to Get-Date at all, which is where the problem arose due to passing a string representation of a date - see next section.
Incidentally, Get-Date -Date directly accepts a [datetime] instance, so there's no need to pass a string.
When you do pass a string, the resulting [datetime] (System.DateTime) has a .Kind property value of Unspecified rather than Local
Specifically, you've run into a problematic inconsistency in from-string type conversions in different contexts:
Casts and script/function parameters use culture-invariant from-string conversion; that is, irrespective of what the current culture is (as reflected in $PSCulture), the rules of the so-called invariant culture are used, whose date formats are based on the US-English culture; therefore, for instance, [datetime] '11/10/2000' is always interpreted as "10 November 2000", i.e., the first token, 11, is interpreted as the month.
However, more international-friendly formats are supported too; e.g.,
[datetime] '2000-11-10' is the equivalent of the above.
Unexpectedly, cmdlet parameters use culture-sensitive from-string conversion.
This discrepancy is a known problem, but it was decided not to fix it, so as not to break backward compatibility - see GitHub issue #3348.

Powershell what is the time format

2017-05-05 12:03:02 -0400 (Fri, 05 May 2017)
what time format is the above in powershell??
i need the same format to compare with today time in powershell.
Get-Date -format
Since this is a follow-up question, you should mention this.
To convert a string containing a datetime based on UTC with a timezone offset,
use [datetime]::ParseExact(). You should change the RegEx from previous Q&A to only contain the datetime without the redundant information in parentheses.
[datetime]::ParseExact("2017-05-05 12:03:02 -0400","yyyy-MM-dd HH:mm:ss zzzzz",$Null)
This will convert to local time (and correctly include the DST aka daylight saving time at that date)
Sample output here with timezone +1 and DST active to:
2017-05-05 18:03:02 +02:00
Or more universal with .ToString('U') and my German locale settings to:
Freitag, 5. Mai 2017 16:03:02
To get the difference to [datetime]::Now simply subtract and choose a property from
> [datetime]::Now - [datetime]::ParseExact("2017-05-05 12:03:02 -0400","yyyy-MM-dd HHH:mm:ss zzzzz",$Null)
Days : 593
Hours : 20
Minutes : 15
Seconds : 35
Milliseconds : 615
Ticks : 513081356156056
TotalDays : 593,844162217657
TotalHours : 14252,2598932238
TotalMinutes : 855135,593593427
TotalSeconds : 51308135,6156056
TotalMilliseconds : 51308135615,6056
You can build more or less any format you like using the DateTime Format Strings and either the format operator (-f) or the ToString() method. For example:
(Get-Date).ToString("yyyy-MM-dd hh:mm:ss")
Which gives something like this:
2018-12-20 12:50:53
If you want to go the other way, you can do it like this:
Get-Date "2017-05-05 12:03:02 -0400"
This converts your string to an actual DateTime object, which can be directly compared to any other DateTime. So, to check if your target date is before now, for example, do something like this:
(Get-Date "2017-05-05 12:03:02 -0400") -lt (Get-Date)

How to convert milliseconds to date and time in powershell?

I want convert milliseconds to date time follow the format mm/dd/yyyy in powershell, my code is below:
$data+= $dataList.Rows[$i]["ROOM_LASTVISITDATE"].ToString() + "`t"
The result of 1278504562790. So, how i can convert it to date time in powershell, please help me. Thanks
To convert a epoch/unix timestamp to a human readable date with Powershell, you can use the DateTimeOffset type.
[datetimeoffset]::FromUnixTimeMilliseconds(1278504562790).DateTime
Your code could then look like this
$lastVisited = $dataList.Rows[$i]["ROOM_LASTVISITDATE"].ToString()
$data += [datetimeoffset]::FromUnixTimeMilliseconds($lastVisited) + "`t"
Assuming the offset is the start of the UNIX epoch (01/01/1970), you could simply add the milliseconds to that offset:
$EpochStart = Get-Date 1970-01-01T00:00:00
$myDateTime = $EpochStart.AddMilliseconds(1278504562790)

Get total mins for today

I am looking for total mins for today,
Tried this way but not working.
$from_date = Get-Date
$Start_date = $from_date.ToShortDateString()
($from_date - $Start_date).Minute
I'd do it this way:
PS C:\> (Get-Date).TimeOfDay.TotalMinutes
651.356536988333
Don't use ToShortDateString() if you want to do further arithmetic cprocessing on the object, it'll turn it into a string.
Substract the Date property from the object and grab the TotalMinutes property value from the resulting timespan:
$from_date = Get-Date
$MinutesSinceMidnight = ($from_date - $from_date.Date).TotalMinutes
The result will be in decimal form. Use Math.Floor() if you need an integer value:
[System.Math]::Floor($MinutesSinceMidnight)