сравнение даты и времени, позволяющее продолжить поток, когда не должно - PullRequest
0 голосов
/ 17 января 2019

У меня есть скрипт резервного копирования, который каждую ночь помещает файлы в устаревший каталог. У меня есть другой скрипт ниже, который просматривает список датированных каталогов, и если он находится в пределах диапазона, который я хочу удалить, я буду удалять каталог, сохраняя файл с датой субботы. По какой-то причине, для каталога от субботы, 12.01.2009, он удаляется, хотя в операторе if должно быть указано, что он не будет удален.

Это мой код:

function WeeklyCleanup($folderWeeklyCleanupDatedSubdirs) {
   #find out date range to cleanup
   $lastSaturday = GetLastSaturdayDate
   $lastSaturday = [datetime]$lastSaturday
   $weekAgoSunday = GetWeekAgoSundayDate
   $weekAgoSunday = [datetime]$weekAgoSunday
   #find out filename with Saturday date before current date but within week
   Get-ChildItem $folderWeeklyCleanupDatedSubdirs | ForEach-Object {
      write-output $_
      #check to see if item is before day we want to remove
      $temp = $_
      $regex = [regex]::Matches($temp,'([0-9]+)-([0-9]+)-([0-9]+)')
      if($regex.length -gt 0) #it matched
      {
         $year  = $regex[0].Groups[1].Value
         $month = $regex[0].Groups[2].Value
         $day   = $regex[0].Groups[3].Value
         write-output $year
         write-output $month
         write-output $day
         write-output "*************"
         $dirDate = $regex[0].Groups[0].Value + " 12:00:00 PM"
         write-output $dirDate

         if($dirDate.length -gt 0) #it matched
         {
            $dateTimeObjectFromRegex = [datetime]$dirDate
########## этот следующий оператор пропускает $ dateTimeObjectFromRegex от 1/12/2019, когда это не должно быть. Смотрите сравнение времени ниже
            if(([datetime]$dateTimeObjectFromRegex -lt [datetime]$lastSaturday) -and ([datetime]$dateTimeObjectFromRegex -ge [datetime]$weekAgoSunday)) #we're removing extra ones over last week, keep Saturday
            {
               $dirPathToRemove = Join-Path -path $folderWeeklyCleanupDatedSubdirs -ChildPath $temp.ToString()
               Get-ChildItem -Path $dirPathToRemove #list the dir
               #remove dir
               if(-Not (Test-Path $dirPathToRemove )) #-PathType Container
               {
                  $global:ErrorStrings.Add("Exception: No such path, $dirPathToRemove;;  ")
                  write-output  "++ Error: An error occured during copy operation. No such path, $dirPathToList ++"
               }
               else
               {
                  #remove dir and subdirs
                  Remove-Item $dirPathToRemove -Force -Recurse
                  Get-ChildItem -Path $dirPathToRemove #list the dir
               }
               #Write-Output $_
               #Write-Output " 1 "
            } #if within last week
         } #if dirDate length
      } #if regex matched

   } #get-childItem
}

function GetLastSaturdayDate()
{
   $date = Get-Date #"$((Get-Date).ToString('yyyy-MM-dd'))"
   #for($i=1; $i -le 7; $i++){
   #   if($date.AddDays(-$i).DayOfWeek -eq 'Saturday') #if found Saturday
   #   {
   #      $date.AddDays(-$i)
   #      $newDate = $date.AddDays(-$i)
   #      break
   #   }
   #}
   $newdate = $date.AddDays(-($date.DayOfWeek+1)%7)
   return $newdate
}

function GetWeekAgoSundayDate()
{
   $numberOfWeeks = 1; #week ago
   $date = Get-Date #"$((Get-Date).ToString('yyyy-MM-dd'))"
   #for($i=1; $i -le 7; $i++){
   #   if(($date.AddDays(-$i).DayOfWeek -eq 'Sunday') -and ($date.AddDays(-$i) -ne  $date)) #if found a Sunday and it's not today
   #   {
   #      $date.AddDays(-$i)
    #     $newDate = $date.AddDays(-$i)
    #     break
    #  }
   #}
   #$newdate = $date.AddDays(-($date.DayOfWeek+1)%0)
   $numDaysSincePreviousDate = $date.DayOfWeek.value__ + 0 #0 is Sunday
   ([System.DateTime] $previousDayOfWeek = $date.AddDays(- $numDaysSincePreviousDate)) | Out-Null
   $previousDate = $previousDayOfWeek.AddDays(-($numberOfWeeks *7)).ToString("MM-dd-yyyy")
   return $previousDate
}

Сценарий WeeklyCleanup вызывается с этим параметром:

$folderToCleanupDatedSubdirs = [System.IO.DirectoryInfo]"E:\Bak_TestDatedFolderCleanup"

Для сравнения времени:

Элемент каталога toLocRobo_2019-01-12 - Получив регулярное выражение с отметкой времени, я добавляю время в 12:00:00 для переменной $ dirDate. Это становится $ dateTimeObjectFromRegex. Отладчик показывает это как суббота, 12 января 2019 года, 12:00:00

Когда я запускаю программу, я получаю $ lastSaturday в субботу, 12 января 2019 года, 15:59:04

Когда я запускаю программу, отладчик также показывает $ weekAgoSunday как воскресенье, 6 января 2019 года, 12:00:00

Из того, что я вижу, не должно пройти через оператор if, чтобы удалить каталог за 1/12/2019.

Я попытался привести даты к datetime, чтобы убедиться, что в операторе if не выполняется сравнение строк, хотя я и приводил их выше.

Я искал эти ссылки для получения дополнительной информации по этому вопросу, но для меня это выглядит правильно:

dateTime Сравнения не работают ожидаемым образом

преобразование строки в дату и время

Все, что я могу думать, это то, что он все еще рассматривает дату и время в первой части сравнения оператора if как строку, поэтому он думает, что 3:59 PM больше, чем 12:00 PM. Любые идеи, как заставить эту дату проверить работу? Меня не волнует время, я просто хочу убедиться, что он не избавится от файла с датой субботы с прошлой недели, а только очистит другие каталоги за эту неделю.

Обновление Внесены изменения, предложенные @brianist ниже, и это сработало замечательно. Вот как это выглядит до сих пор. Функции субботы и воскресенья не изменились. Он просит меня опубликовать это. Если у него есть какие-либо другие предложения, как заставить его обрабатывать / сравнивать то, что возвращается с прошлой субботы, а функция WeekAgoSunday работает как даты, без приведения, это сделало бы его менее неуклюжим / легче читаемым. Спасибо, Брайан!

#do weekly cleanup of DisasterBackup folder
function WeeklyCleanup($folderWeeklyCleanupDatedSubdirs) {
   #find out current date
   $currentDate = "$((Get-Date).ToString('yyyy-MM-dd'))"  #example 2019-01-15
   $currentDayOfWeek = (get-date).DayOfWeek.value__ #returns int value for day of week
   #find out current day of week
   $lastSaturday = GetLastSaturdayDate
   $lastSaturday = [datetime]$lastSaturday #if we take away extra casts it won't do comparison line (-lt and -ge)
   $weekAgoSunday = GetWeekAgoSundayDate
   $weekAgoSunday = [datetime]$weekAgoSunday #if we take away extra casts it won't do comparison line (-lt and -ge), and can't move cast before function call because it isn't recognizing function anymore if I do
   #find out filename with Saturday date before current date but within week
   #get each dir item to check if we need to remove it
   Get-ChildItem $folderWeeklyCleanupDatedSubdirs | ForEach-Object {
      write-output $_
      #check to see if item is before day we want to remove
      $temp = $_
      if($_.Name -match '(\d{4}-\d{2}-\d{2})$'){ #regex
         write-output $Matches[1]
         $dirDate = Get-Date $Matches[1] #turn regex into date
         if(([datetime]$dirDate.Date -lt [datetime]$lastSaturday.Date) -and ([datetime]$dirDate.Date -ge [datetime]$weekAgoSunday.Date)) #we're removing extra ones over last week, keep Saturday
         {
            $dirPathToRemove = Join-Path -path $folderWeeklyCleanupDatedSubdirs -ChildPath $temp.ToString()
            Get-ChildItem -Path $dirPathToRemove #list the dir
            #remove dir
            if(-Not (Test-Path $dirPathToRemove )) #-PathType Container
            {
               $global:ErrorStrings.Add("Exception: No such path, $dirPathToRemove;;  ")
               write-output  "++ Error: An error occured during copy operation. No such path, $dirPathToList ++"
            }
            else
            {
               #remove dir and subdirs
               Remove-Item $dirPathToRemove -Force -Recurse
               Get-ChildItem -Path $dirPathToRemove #list the dir
            }

         } #if within last week
      } #if regex matched

   } #get-childItem
}

1 Ответ

0 голосов
/ 17 января 2019

Перечитывая ваше последнее предложение, я теперь вижу, что ваше намерение состоит в том, чтобы игнорировать времена, а не включать их в ваше сравнение.

Вы вправе использовать [DateTime] объекты при сравнении, но учтите, что эти объекты всегда включают время.

Удобно, что вы можете использовать свойство .Date такого объекта, который возвращает новый, со временем, установленным в полночь. Это полезно для сравнения, потому что время больше не будет фактором.

Вытащив мое модифицированное утверждение if снизу, вы можете сделать это так:

if ($dirDate.Date -lt $lastSaturday.Date -and $dirDate.Date -ge $weekAgoSunday.Date) {
    # do stuff
}

Теперь вы сравниваете только даты и игнорируете время!


Исходя из того, что вы показываете, похоже, что оператор if работает, как ожидалось. Подводя итог, вы говорите, что:

$dateTimeObjectFromRegex - это Saturday, January 12, 2019 12:00:00 PM

$lastSaturday - это Saturday, January 12, 2019 3:59:04 PM

$weekAgoSunday - это Sunday, January 6, 2019 12:00:00 AM

Условное значение:

if(([datetime]$dateTimeObjectFromRegex -lt [datetime]$lastSaturday) 
-and ([datetime]$dateTimeObjectFromRegex -ge [datetime]$weekAgoSunday))

Поэтому в псевдокоде это:

if (
    ("January 12, 2019 12:00:00 PM" is earlier than "January 12, 2019 3:59:04 PM") # true
    and
    ("January 12, 2019 12:00:00 PM" is later or the same as "January 6, 2019 12:00:00 AM") # true
) # true

Я хочу отметить, что вы выполняете очень много ненужных операций по сбору и преобразованию даты и времени, и их очистка поможет улучшить читаемость и устранить проблемы такого типа.

$lastSaturday = GetLastSaturdayDate
$lastSaturday = [datetime]$lastSaturday
$weekAgoSunday = GetWeekAgoSundayDate
$weekAgoSunday = [datetime]$weekAgoSunday

Ваши функции уже возвращают [DateTime] объектов, поэтому нет необходимости в этих приведениях.


      $temp = $_
      $regex = [regex]::Matches($temp,'([0-9]+)-([0-9]+)-([0-9]+)')
      if($regex.length -gt 0) #it matched
      {
         $year  = $regex[0].Groups[1].Value
         $month = $regex[0].Groups[2].Value
         $day   = $regex[0].Groups[3].Value
         write-output $year
         write-output $month
         write-output $day
         write-output "*************"
         $dirDate = $regex[0].Groups[0].Value + " 12:00:00 PM"
         write-output $dirDate

Это довольно сложно, вы можете упростить его до чего-то вроде этого:

if ($_.Name -match '(\d{4}-\d{2}-\d{2})$') {
    # in here, you know the match was successful
    $dirDate = Get-Date $Matches[1] # double check this, might need .Groups or something

    if ($dirDate -lt $lastSaturday -and $dirDate -ge $weekAgoSunday) {
        # do stuff
    }
}

Возможно, еще несколько оптимизаций и т. Д. Надеюсь, это было полезно!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...