1

As I have mentioned in the Question title, I want to convert the ConvertFrom-Json command's output to string such that, the character/string I get, should be usable such that it can be inserted into DateTime string as replacement to another character.

Currently I have following code to get the present DateTime:

$DTCurr = (Get-Date).tostring("dd-MM-yyyy_hh+mm+ss")

Now in the above code, I want to force replace the plus sign with colon sign, such that the resulting DateTime string can be used in the file-naming, so I am expecting the output(after replacement) like below:

07-11-2020_12:59:13

Now I tried this code for that forced replacement, but it doesn't work:

$colon = ('{ "str": "\uA789" }' | ConvertFrom-Json)
$DTCurr = (Get-Date).tostring("dd-MM-yyyy_hh+mm+ss")
$DTCurr = $DTCurr -replace "\+",$colon
Echo $DTCurr

This gives the output: 07-11-2020_02@{str=꞉}06@{str=꞉}28 which is ridiculous and unexpected. I can assure that $colon does print : when passed to Echo.

Can someone let me know what I doing wrong and help out achieve this ?

Vicky Dev
  • 1,893
  • 2
  • 27
  • 62

2 Answers2

2

Sorry if I'm misconstruing this, but I think your end goal can be simplified by doing this

$DTCurr = (Get-Date).tostring("dd-MM-yyyy_hh:mm:ss")

or this

$DTCurr = (Get-Date).tostring("dd-MM-yyyy_hh+mm+ss")
$colonDT = $DTCurr -replace "\+",":"

but if you wanna do it your way, the reason why it's printing that output, is because it's doing exactly what you're telling it to do. You're replacing the + with an object that has a property named str with a value of :. You would need to do this instead

$colon = ('{ "str": "\uA789" }' | ConvertFrom-Json)
$DTCurr = (Get-Date).tostring("dd-MM-yyyy_hh+mm+ss")
$colonDT = $DTCurr -replace "\+",$colon.str
Echo $colonDT

If I am incorrect, and you need more assistance, let me know.

PowerShellGuy
  • 733
  • 2
  • 8
  • Perhaps you didn't get the full idea of question. In Windows there's no allowance of using colon directly in file-naming convention, but using this Unicode character I mentioned in the question, it can interpret exactly like colon, but can fool Windows in thinking that it's not colon and can be used in file-renaming, I want exactly that. Let me know if anything still unclear. – Vicky Dev Nov 06 '20 at 20:49
  • just did a ninja edit before I saw this new comment. Any reason why you would want colons in the file name? There are better datetime formats for organizing files. – PowerShellGuy Nov 06 '20 at 20:53
  • The last section should do what you initially intended though. – PowerShellGuy Nov 06 '20 at 20:54
  • I guess I have bit too much of Linux/Unix fever :) They do allow literally any char incl. colons in filenames which are inherited in GitBash and Msysgits, which I wanted to repliacte with Powershell, after I was disappointed with Batch/Cmd, so I went at this adventure,and thanks you did helped me out and it worked. – Vicky Dev Nov 06 '20 at 20:56
  • 1
    Kinda off topic, but I would recommend you stick with the ISO 8601 standard (or a slight variation of it) for your filenames. unicode colon works, but it's kinda hacky. A 'pure' example would look like `20201106T1600`. Because we're (I assume) both humans, that's not so easy on the eyes, so I would opt for something like `2020-11-06_1400` or `20201106_1400` or other variants. – PowerShellGuy Nov 06 '20 at 21:02
  • Yup, your suggestion is correct, but it's just that I'm habituated for years working as programmer, seeing the time string always decorated with colons, even sometimes seeing Time in other formats makes me question my code output, I've majorly worked in Unix/Linux for coding.. – Vicky Dev Nov 06 '20 at 21:07
1

PowerShellGuy's helpful answer solves your problem; let me complement it:

tl;dr

# Use a [char] cast with the Unicode code point to create the char.
# of interest - no need for using JSON for that.
PS> (Get-Date).ToString('dd-MM-yyyy_hh+mm+ss') -replace '\+', [char] 0xA789
06-11-2020_09꞉17꞉25

It seems that the sole reason you're using a JSON representation is to get a string with a Unicode character beyond the ANSI/ASCII-range, namely (MODIFIER LETTER COLON, U+A789), which looks just like the ASCII-range : (COLON, U+003A), but isn't.

If we assume that you need this JSON detour - which you don't - the simplest solution would have been:

$colonSubstitute = '"\uA789"' | ConvertFrom-Json

The JSON detour isn't needed, because you can cast Unicode code points directly to [char] (System.Char):

# Directly creates Unicode char. U+A789 as a [char] (System.Char) instance.
$colonSubstitute = [char] 0xA789

You could cast that to a [string] instance, though that is often not necessary, given PowerShell's automatic, flexible type conversions (see below):

$colonSubstitute = [string] [char] 0xA789

PowerShell [Core] v6+ directly supports Unicode escape sequences (akin to JSON's) inside double-quoted strings ("..."), also known as expandable (interpolating) strings, using the syntax `u{n}, where n is the character's Unicode code point:

# PowerShell [Core] v6+ escape sequence
# Same as:         "$([char] 0xA789)"
$colonSubstitute = "`u{A789}"

Note: Unlike [char] casts, the `u{n} syntax also supports characters beyond the Unicode BMP (Basic Multilingual Plane), i.e., characters with code points greater than U+FFFF (0xFFFF); e.g., "`u{1F913}" for . However, in the resulting (expanded) string such characters are represented as two [char] (System.Char) instances, so-called surrogate pairs, because .NET characters are UTF-16, i.e. 16-bit code units with a max. value of 0xFFFF and therefore cannot directly represent non-BMP characters; thus, for instance, "`u{1F913}".Length yields 2.


In Windows PowerShell, you can use $(...), the subexpression operator, to embed [char] casts inside double-quoted strings ("..."):

$colonSubstitute = "$([char] 0xA789)"

Note: As discussed, [char] (System.Char) casts are limited to characters in the Unicode BMP. While characters in the non-BMP range (code points 0x10000 and up) are rare overall, you do need them for emoji, such as (NERD FACE , U+1F913). Unlike the PowerShell [Core] v6+ syntax, using [char] casts to represent surrogate pairs is neither obvious nor convenient:

For instance, to represent , you must (a) know that non-BMP code point U+1F913 is represented as UTF-16 surrogate pair 0xD83E, 0xDD13, and then embed the latter in either of these two forms:
"$(-join [char[]] (0xD83E, 0xDD13))" or "$([char] 0xD83E)$([char] 0xDD13)"


Finally, given PowerShell's automatic, flexible type conversions, you can directly use a [char] instance as the operands of the -replace operator:

PS> (Get-Date).ToString('dd-MM-yyyy_hh+mm+ss') -replace '\+', [char] 0xA789
06-11-2020_09꞉17꞉25
mklement0
  • 382,024
  • 64
  • 607
  • 775