使用SqlDataAdapter填充DataSet正在更改日期格式

时间:2017-03-20 22:34:06

标签: sql-server powershell datetime

我在网上搜索过,无法找到问题的解决方案/指南。

我正在使用以下位脚本作为更大脚本的一部分将多个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导出到一个平面文件中,数据显示与使用导出向导时完全相同。

2 个答案:

答案 0 :(得分:2)

更改脚本中的默认DateTime格式

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

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

此字符串的格式由您特定的全球化" culture"指定(正如您制定的那样)。它似乎是 DateTimeFormat ShortDatePattern LongTimePattern 属性的串联。

有很多人尝试过但未能改变当前会话的文化(即正在运行的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问题的例子中运行它,但是我已经玩得很开心了。 ; - )

答案 1 :(得分:0)

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

与Java相比,我来自Java世界的更多,但我不得不编写一个脚本来导出db CSV,这是我的调查,以防其他人对格式的构建感兴趣。我研究了源代码,以了解ToStringDateTime上的工作方式。

根据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); }

这最终将使用Format null String调用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对象,该对象具有无法覆盖的内部String模式。它懒惰地设置它,以便它不必连接,也没有办法覆盖它。正如查理指出的那样,它总是将ShortDatePatternLongTimePattern用空格分隔符连接起来。 https://referencesource.microsoft.com/#mscorlib/system/globalization/datetimeformatinfo.cs,799bd6e7997c4e78

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

因此,您已经拥有了它。希望它可以帮助下一个人知道原因/方式,并且不可能覆盖整个默认格式-仅覆盖日期和时间部分。