检查输入和返回数据类型的Powershell函数未返回正确的值

问题描述 投票:0回答:2

我正在使用 powershell 脚本来协助数据库更新/解析等。因为我们的数据库服务器不允许我们在同一脚本中进行查询和更新,所以我需要实际查询数据,使用 powershell 在我的计算机上解析它,然后根据解析的查询构建一个新的更新语句。为了帮助解决这个问题,我需要在 powershell 和 SQL 之间正确转换数据类型。我编写了以下函数来协助解决此问题,但它没有正确解析时间戳,并且传递给它的任何时间戳都会导致函数返回“字符串”并将 $setDate 变量保留为 $null

$myDate = '5/10/2023'

function getDataType {
   param($inputData)
   
   #check if input data is null
   if (!$inputData) {
      return 'null'
   }
   
   #check if variable can be cast as a timestamp
   try {
      #build an array of possible timestamp formats
      $dateFormats = @('M/d/yyyy','M/dd/yyyy','MM/d/yyyy','MM/dd/yyyy','MM-dd-yyyy HH:mm:ss','MM-dd-yyyy HH:mm','yyyy-MM-dd HH.mm.ss')
      
      foreach ($format in $dateFormats) {
         if ([DateTime]::TryParseExact($inputData, $format, $null)) {
            $global:setDate = [datetime]::ParseExact($inputData, $format, $null).ToString('yyyy-MM-dd HH:mm:ss')
            return 'timestamp'
            break
         }
      }
   }
   catch {
      write-verbose 'not a timestamp'
   }
   
   #check if data is a number
   try {
      if ([int]$inputData) {
         return 'number'
      }
   }
   catch {
      write-verbose 'not a number'
   }
   
   #assumes input is a string if it is not null, not a date, and not a number
   return 'string'
}

getDataType($myDate) #should return 'timestamp' but returns 'string'

write-host "the date is $setDate" #should return "the date is 2023-05-10 00:00:00" but returns nothing
powershell
2个回答
2
投票

您的代码的主要问题是您缺少

[DateTime]::TryParseExact
调用的参数并引发错误,您只是没有看到它,因为
Write-Verbose
没有
-Verbose
参数来生成详细输出,一个最小的例子:

try {
    [DateTime]::TryParseExact('5/10/2023', 'M/dd/yyyy', $null)
}
catch {
    Write-Verbose 'not a timestamp' -Verbose
}

# Outputs: VERBOSE: not a timestamp

正确的方法调用是将缺少的参数添加到此重载中:

[DateTime]::TryParseExact(
    '5/10/2023',                                 # string s
    'M/dd/yyyy',                                 # string? format
    [cultureinfo]::InvariantCulture,             # IFormatProvider? provider
    [System.Globalization.DateTimeStyles]::None, # DateTimeStyles style
    [ref] [datetime] 0)                          # out DateTime result

您似乎还想重复调用此函数,您应该注意重复的函数调用是昂贵的,因为我建议您将函数更改为静态方法,这样就不会受到影响这。这是您想要完成的工作版本:

class MyType {
    static [string[]] $Formats = @(
        'M/d/yyyy'
        'M/dd/yyyy'
        'MM/d/yyyy'
        'MM/dd/yyyy'
        'MM-dd-yyyy HH:mm:ss'
        'MM-dd-yyyy HH:mm'
        'yyyy-MM-dd HH.mm.ss'
    )

    static [string] GetDataType([object] $inputData, [ref] $out) {
        if([string]::IsNullOrWhiteSpace($inputData)) {
            return 'null or empty string'
        }

        if([int]::TryParse($inputData, [ref] $null)) {
            return 'its an integer'
        }

        # no need for a loop here, `TryParseExact` has an `string?[]? formats` overload for this ;)
        $isDate = [datetime]::TryParseExact(
            $inputData,
            [MyType]::Formats,
            [cultureinfo]::InvariantCulture,
            [System.Globalization.DateTimeStyles]::None, # You should define this one
            $out)

        if($isDate) {
            return 'its a datetime'
        }

        return 'undetermined string'
    }
}

$myDate = '5/10/2023'
$myOutVar = [datetime]::new(0)
$result = [MyType]::GetDataType($myDate, [ref] $myOutVar)

if($result -eq 'its a datetime') {
    return $myOutVar
}

$result

0
投票

如果您不需要指定自定义日期时间格式,则像 Get-Date cmdlet 这样的东西应该捕获有效的日期和时间戳。如果您想考虑使用 Get-Date 时会失败的句点格式,请使用像这样的替换...

# Below example captured all dates in desired string format
$SetDates = @(
    '5/9/2023',
    '5/10/2023',
    '05/9/2023',
    '05/10/2023',
    '05-10-2023 12:05:02',
    '05-10-2023 12:05',
    '2023-05-10 12.05.02'
) | ForEach-Object { 
      Get-Date -Date $($_ -replace '\.',':') -Format 'yyyy-MM-dd HH:mm:ss'
}

$设置日期

2023-05-09 00:00:00
2023-05-10 00:00:00
2023-05-09 00:00:00
2023-05-10 00:00:00
2023-05-10 12:05:02
2023-05-10 12:05:00
2023-05-10 12:05:02
© www.soinside.com 2019 - 2024. All rights reserved.