我在网上搜索过,无法找到问题的解决方案/指南。
我正在使用以下位脚本作为更大脚本的一部分将多个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导出到一个平面文件中,数据显示与使用导出向导时完全相同。
答案 0 :(得分:2)
在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,这是我的调查,以防其他人对格式的构建感兴趣。我研究了源代码,以了解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);
}
这最终将使用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模式。它懒惰地设置它,以便它不必连接,也没有办法覆盖它。正如查理指出的那样,它总是将ShortDatePattern
和LongTimePattern
用空格分隔符连接起来。
https://referencesource.microsoft.com/#mscorlib/system/globalization/datetimeformatinfo.cs,799bd6e7997c4e78
internal String GeneralLongTimePattern {
get {
if (generalLongTimePattern == null) {
generalLongTimePattern = ShortDatePattern + " " + LongTimePattern;
}
return (generalLongTimePattern);
}
}
因此,您已经拥有了它。希望它可以帮助下一个人知道原因/方式,并且不可能覆盖整个默认格式-仅覆盖日期和时间部分。