【问题标题】:Filling DataSet using SqlDataAdapter is changing the date format使用 SqlDataAdapter 填充 DataSet 正在更改日期格式
【发布时间】:2018-11-09 08:10:34
【问题描述】:

我在整个网络上进行了搜索,但找不到针对我的问题的解决方案/指南。

我正在使用下面的脚本,它是一个较大脚本的一部分,将多个 SQL 表导出到 CSV。它使用 SQL 表中的数据填充数据集。

我遇到的问题主要与日期时间设置有关。例如,如果我要使用导出向导将 SQL 表导出到 CSV 文件中。日期的显示与 SQL 中的完全相同,例如“2014-05-23 07:00:00.0000000”或“2014-05-23”。

但是,当我使用我的脚本时,它会将日期时间的格式更改为“23/05/2014 07:00:00”或“23/05/2014 00:00:00”。我相信这与我的机器/powershell 会话的文化设置有关。

cls

# Declare variables for connection and table to export
$Server     = 'server'
$Database   = 'database'
$Folder     = 'D:\Powershell Scripts\01_Export From SQL\Test Folder'
$Tablename1 = 'test'
$Tablename2 = ''

# Delcare Connection Variables
$SQLconnection = New-Object System.Data.SqlClient.SqlConnection
$SQLconnection.ConnectionString = "Integrated Security=SSPI;server=$Server;Database=$Database"

# Delcare SQL command variables
$SQLcommand = New-Object System.Data.SqlClient.SqlCommand 
$SQLcommand.CommandText = "SELECT [name] from sys.tables where [name] like '%$Tablename1%' and [name] like '%$Tablename2%' order by [name]"
$SQLcommand.Connection = $SQLconnection 

# Load up the Tables in a dataset
$SQLAdapter = New-Object System.Data.SqlClient.SqlDataAdapter 
$SQLAdapter.SelectCommand = $SQLcommand 
$DataSet = New-Object System.Data.DataSet 
$null = $SqlAdapter.Fill($DataSet)
$SQLconnection.Close()

"Time to Export`tRecords   `tFile Name"
"--------------`t-------   `t---------"

foreach ($Table in $DataSet.Tables[0])
{

    $stopwatch = [system.diagnostics.stopwatch]::StartNew()

    $FileExtractUTF8 = "$Folder\FromPSUTF8_$($Table[0]).csv"
    $SQLcommand.CommandText = "SELECT * FROM [$($Table[0])]"

    $SQLAdapter = New-Object System.Data.SqlClient.SqlDataAdapter
    $SQLAdapter.SelectCommand = $SQLcommand 

    $DataSet = New-Object System.Data.DataSet 
    $Count = $SQLAdapter.Fill($DataSet)              
    $SQLconnection.Close() 

    $DataSet.Tables[0]  | Export-Csv $FileExtractUTF8 -NoTypeInformation -Encoding UTF8        

    $stopwatch.stop()

    $Time = "{0}" -f $stopwatch.Elapsed.ToString('mm\:ss\.fff')

    “{0,-14}`t{1,-10}`t{2}” -f $Time,$Count,$Table.name
}

主要目标是将数据从 SQL 导出到一个平面文件中,数据的显示方式与我使用导出向导时完全一样。

【问题讨论】:

  • 它必须是你的 powershell 脚本,需要看到它。
  • 请查看更新后的帖子。
  • Export-Csv Cmdlet 只是转储文件。您必须以您需要的格式输出每个字段。
  • 或者不只是选择 *,而是使用 SQL 将日期格式化为 convert(varchar(30),YourDateField,120) 为 NewDateFormatted
  • 我已经尝试过了,但它仍然会产生问题。例如,列数据类型 Datetime 在 sql 中显示为“2000-01-01 00:00:00.000”,将该字段转换为 varchar(255) 会将格式更改为“Jan 1 2000 12:00AM”。这是在 SQL 中完成的,甚至在它接触到 powershell 之前。我没有应用任何样式,因为我的目标是保持表格中的原始格式。

标签: sql-server powershell datetime


【解决方案1】:

在脚本中更改默认的 DateTime 格式

在您的 DataSet / DataTable 中,日期以 [DateTime] 类型存在。当您导出为 CSV 时,需要将其转换为字符串,以便将其写入文件。正如您所观察到的,默认字符串转换会给出如下输出:

[PS]> (get-date).ToString()
21/03/2017 17:52:26

此字符串的格式由您的特定全球化“文化”指定(如您所计算的那样)。它似乎是 DateTimeFormatShortDatePatternLongTimePattern 属性的串联。

有很多帖子来自尝试改变当前会话文化但失败的人(即正在运行的 PS 主机)...

...但您的脚本可能会使用如下所述的机制来改变全球化文化:

我怀疑您应该能够使用Using-Culture 示例将Export-Csv 行包装到您的脚本中。

但是使用什么文化呢?

所以,您现在或许可以设置特定的文化,但是任何预先存在的文化是否使用 ISO8601(可排序)日期?或者更具体的格式?好像不行,得自己做!

简而言之,您需要克隆现有的CultureInfo 并更新DateTimeFormat,特别是(至少)ShortDatePattern 成为您想要的。这是一个例子,我希望能让你走上正确的道路。有两个函数,一个是克隆现有的 CultureInfo,另一个是使用新的文化集运行命令 (Get-Date)为该线程


function New-CultureInfo {
  [CmdletBinding()]
  [OutputType([System.Globalization.CultureInfo])]
  param(
    [Parameter()]
    [System.Globalization.CultureInfo]
    $BaseCulture = [System.Globalization.CultureInfo]::InvariantCulture
  )

  $CultureInfo = ($BaseCulture).Clone()

  $CultureInfo.DateTimeFormat.ShortDatePattern = "yyyy'-'MM'-'dd"
  $CultureInfo.DateTimeFormat.LongTimePattern = "HH:mm:ss.fff"

  return $CultureInfo
}

function Test-DateFormat {
  [CmdletBinding()]
  [OutputType([System.DateTime])]
  param(
    [Parameter(Mandatory)]
    [System.Globalization.CultureInfo]
    $Culture
  )

  [System.Threading.Thread]::CurrentThread.CurrentUICulture = $Culture
  [System.Threading.Thread]::CurrentThread.CurrentCulture = $Culture

  (Get-Date).ToString()
}

使用示例:

[PS]> $NewCulture = (New-CultureInfo)

[PS]> Test-DateFormat $NewCulture
2017-03-21 19:08:34.691

现在,我无法针对接近 OP 中的 SQL 问题的示例运行此程序,但我很享受完成这一切的乐趣。 ;-)

【讨论】:

  • 听着,我不会假装我明白这一点。但是我在深夜将您的代码复制并粘贴到了我的 powershell 脚本中,该脚本正在转储 2500 个表。我竭尽全力想弄清楚我到底要如何修复 2500 张日期不好的桌子。这就像一个绝对的魅力。你真是个天才!谢谢你。我保证我会回来并在某个时候真正尝试理解它。谢谢!
【解决方案2】:

查理的精彩描述。我的问题是我想更改默认的ToString 以输出一个ISO 日期时间,其中包含日期和时间之间的T 分隔符而不是空格。 TL;DR - 这是不可能的。

我更多来自 Java 世界而不是 MS,但我必须编写一个脚本来导出 db CSV,如果其他人对如何构建格式感兴趣,这是我的调查。我深入研究了源代码以了解ToString 如何在DateTime 上工作。

根据DateTime 类,它将遵循DateTimeFormat https://referencesource.microsoft.com/#mscorlib/system/datetime.cs,0a4888bea7300518

public override String ToString() { Contract.Ensures(Contract.Result<String>() != null); return DateTimeFormat.Format(this, null, DateTimeFormatInfo.CurrentInfo); }

这最终将使用null String format 调用Format 方法。这会导致下面的块被调用,它基本上指定了"G" 格式用于日期/时间。 https://referencesource.microsoft.com/#mscorlib/system/globalization/datetimeformat.cs,386784dd90f395bd if (offset == NullOffset) { // Default DateTime.ToString case. if (timeOnlySpecialCase) { format = "s"; } else { format = "G"; } }

这最终将调用以获取当前 Culture 的 DateTimeInfo 对象,该对象具有无法覆盖的内部字符串模式。它懒惰地设置它,因此它不必连接并且没有办法覆盖它。正如查理指出的那样,它总是用空格分隔符连接ShortDatePatternLongTimePatternhttps://referencesource.microsoft.com/#mscorlib/system/globalization/datetimeformatinfo.cs,799bd6e7997c4e78

internal String GeneralLongTimePattern { get { if (generalLongTimePattern == null) { generalLongTimePattern = ShortDatePattern + " " + LongTimePattern; } return (generalLongTimePattern); } }

所以你有它。希望它可以帮助下一个人知道为什么/如何,并且不可能覆盖整体默认格式 - 只是日期和时间组件。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-04
    • 2016-04-16
    相关资源
    最近更新 更多